﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace daSyntaxAnalyser.Analysers
{
    // Объекты, синтаксическое дерево и анализаторы
    using SyntaxTree;
    using daBase.Objects;
    using daBase.Analyser;

    /// <summary>
    /// Синтаксический анализатор
    /// </summary>
    [AnalyserDefaultSettings("Синтаксический анализатор", "Неожиданная последовательность токенов!", 100, "Анализатор не в состоянии распознать данную последовательность ключевых слов. Возможно она некорректна или анализатор работает неправильно. Сообщите о данной ошибке разработчику.")]
    public class SyntaxAnalyser : LayerAnalyser
    {
        // Текущий токен
        private int current;

        // Подгружать модули
        private bool loadIfNeed;

        // Собирать токены или нет
        private bool collectcomments;

        // Все токены
        private List<TokenInfo> comments, tokens;

        /// <summary>
        /// Сброс анализатора
        /// </summary>
        public void Reset()
        {
            file = null;
            tokens.Clear();
        }

        /// <summary>
        /// Получить все комментарии
        /// </summary>
        /// <returns>список токенов комментариев</returns>
        private List<TokenInfo> GetComments()
        {
            if (comments.Count > 0)
            {
                List<TokenInfo> temp = comments;
                comments = new List<TokenInfo>();
                return temp;
            }
            else return null;
        }

        /// <summary>
        /// Инициализация анализатора
        /// </summary>
        private void Initialize(string file, bool loadIfNeed)
        {
            this.loadIfNeed = loadIfNeed;
            this.file = file;
            collectcomments = true;
            if (comments == null)
                comments = new List<TokenInfo>();
            else comments.Clear();
            tokens = LexicalAnalyser.Instance.Translate(file, File.ReadAllText(file, Encoding.Default));
            current = 0;
        }

        /// <summary>
        /// Может ли токен быть идентификатором
        /// Некоторые токены могут быть и ключевым словом и идентификатором
        /// </summary>
        /// <param name="t">токен</param>
        /// <returns>результат</returns>
        private bool TokenCanBeId(DelphiTokens t)
        {
            switch (t)
            {
                case DelphiTokens.Name:
                case DelphiTokens.Register:
                case DelphiTokens.Message:
                case DelphiTokens.Read:
                case DelphiTokens.Write:
                case DelphiTokens.Default:
                case DelphiTokens.ReadOnly:
                case DelphiTokens.Index:
                case DelphiTokens.Reference:
                    return true;
                default:
                    return false;
            }
        }
        /// <summary>
        /// Является ли токен "экстра" токеном
        /// "экстра" токен - токен, который не может быть объявлен как Id, но это не мешает его использованию в качестве Id
        /// </summary>
        /// <param name="t">токен</param>
        /// <returns>результат</returns>
        private bool IsExtraToken(DelphiTokens t)
        {
            switch (t)
            {
                case DelphiTokens.End:
                case DelphiTokens.Object:
                    return true;
                default:
                    return false;
            }
        }

        /// <summary>
        /// Пропуск комментариев
        /// </summary>
        /// <returns>количество пропущенных комментариев</returns>
        private int SkipComments(int index)
        {
            while (true)
            {
                switch (tokens[index].Token)
                {
                    case DelphiTokens.LComment:
                    case DelphiTokens.MLComment:
                    case DelphiTokens.OComment:
                    case DelphiTokens.BComment:
                        if (collectcomments)
                            comments.Add(tokens[index]);
                        index++;
                        break;
                    default:
                        return index;
                }
            }
        }

        /// <summary>
        /// Сравнение двух токенов
        /// </summary>
        /// <returns>результат сравнения</returns>
        private bool MatchTokens(DelphiTokens t1, DelphiTokens t2)
        {
            return ((t1 == t2) || ((t1 == DelphiTokens.Id) && TokenCanBeId(t2)) || ((t2 == DelphiTokens.Id) && TokenCanBeId(t1)));
        }

        /// <summary>
        /// Сравшение токена с последним считанным
        /// </summary>
        /// <param name="t">токен, сравниваемые с последним</param>
        /// <returns>результат сравнения</returns>
        private bool MatchTokens(DelphiTokens t)
        {
            return MatchTokens(tokens[current].Token, t);
        }

        /// <summary>
        /// Считывание токена с заглядыванием назад
        /// </summary>
        /// <param name="t">предыдущий токен</param>
        private void Match(DelphiTokens t)
        {
            if (MatchTokens(t)) current++;
            else Panic();
            current = SkipComments(current);
        }

        /// <summary>
        /// Считывание экстра токена
        /// </summary>
        private void ExtraMatch()
        {
            if (MatchTokens(DelphiTokens.Id) || IsExtraToken(tokens[current].Token))
                current++;
            else Panic();
            current = SkipComments(current);
        }

        /// <summary>
        /// Считывание токена с заглядыванием назад
        /// </summary>
        /// <returns>следующий токен</returns>
        private DelphiTokens MatchAhead()
        {
            if (tokens.Count <= current)
                return DelphiTokens.Undefined;
            collectcomments = false;
            DelphiTokens temp = tokens[SkipComments(current + 1)].Token;
            collectcomments = true;
            return temp;
        }

        ////////////////////////////////////////////////////////
        //////////////////////// АНАЛИЗ ////////////////////////
        ////////////////////////////////////////////////////////

        /// <summary>
        /// Безнаковое целое
        /// </summary>
        /// <returns>соответствующий токен</returns>
        private TokenInfo Int()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.Digits:
                case DelphiTokens.HexConstant:
                    int index = current;
                    Match(tokens[current].Token);
                    return tokens[index];
                default:
                    Panic();
                    return null;
            }
        }

        /// <summary>
        /// Знаковое целое
        /// </summary>
        /// <returns>выражение</returns>
        private ConstExpressionElement SignedInt()
        {
            List<TokenInfo> Tokens = new List<TokenInfo>();
            TokenInfo Start = tokens[current];
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Addition:
                    case DelphiTokens.Subtraction:
                        Tokens.Add(tokens[current]);
                        Match(tokens[current].Token);
                        break;
                    default:
                        Tokens.Add(Int());
                        return new ConstExpressionElement(Start, Tokens, GetComments());
                }
            }
        }

        /// <summary>
        /// Беззнаковое число
        /// </summary>
        /// <returns>набор токенов, входящих в выражение</returns>
        private TokenInfo Real()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.Digits:
                case DelphiTokens.HexConstant:
                case DelphiTokens.Real:
                case DelphiTokens.Exponent:
                    int index = current;
                    Match(tokens[current].Token);
                    return tokens[index];
                default:
                    Panic();
                    return null;
            }
        }

        /// <summary>
        /// Знаковое число
        /// </summary>
        /// <returns>выражение</returns>
        private ConstExpressionElement SignedReal()
        {
            List<TokenInfo> Tokens = new List<TokenInfo>();
            TokenInfo Start = tokens[current];
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Addition:
                    case DelphiTokens.Subtraction:
                        Tokens.Add(tokens[current]);
                        Match(tokens[current].Token);
                        break;
                    default:
                        Tokens.Add(Real());
                        return new ConstExpressionElement(Start, Tokens, GetComments());
                }
            }
        }

        /// <summary>
        /// Строка
        /// </summary>
        /// <returns>выражение</returns>
        private ConstExpressionElement Str()
        {
            List<TokenInfo> String = new List<TokenInfo>();
            if (!MatchTokens(DelphiTokens.String) && !MatchTokens(DelphiTokens.Char))
                Panic();
            TokenInfo Start = tokens[current];
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.String:
                    case DelphiTokens.Char:
                        String.Add(tokens[current]);
                        Match(tokens[current].Token);
                        break;
                    default:
                        return new ConstExpressionElement(Start, String, GetComments());
                }
            }
        }

        /// <summary>
        /// Константа
        /// </summary>
        /// <returns>выражение</returns>
        private ConstExpressionElement Const()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.String:
                case DelphiTokens.Char:
                    return Str();
                case DelphiTokens.True:
                case DelphiTokens.False:
                    return Bool();
                default:
                    return SignedReal();
            }
        }

        /// <summary>
        /// Целая константа
        /// </summary>
        /// <returns>тип константы - идентификатор или число</returns>
        private TokenInfo IInt()
        {
            TokenInfo Token = tokens[current];
            if (MatchTokens(DelphiTokens.Digits) || MatchTokens(DelphiTokens.HexConstant) || MatchTokens(DelphiTokens.Id))
                Match(tokens[current].Token);
            else Panic();
            return Token;
        }

        /// <summary>
        /// Аналогично - целая знаковая константа
        /// </summary>
        /// <returns>выражение</returns>
        private ConstExpressionElement SignedIInt()
        {
            List<TokenInfo> Tokens = new List<TokenInfo>();
            TokenInfo Start = tokens[current];
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Addition:
                    case DelphiTokens.Subtraction:
                        Tokens.Add(tokens[current]);
                        Match(tokens[current].Token);
                        break;
                    default:
                        Tokens.Add(IInt());
                        return new ConstExpressionElement(Start, Tokens, GetComments());
                }
            }
        }

        /// <summary>
        /// В случае external модификатора могут быть указаны индекс или имя
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private ExternalOptionElement OptionalExternalOption()
        {
            TokenInfo Type = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Name:
                    Match(DelphiTokens.Name);
                    return new NameExternalOptionElement(Type, Expression(), GetComments());
                case DelphiTokens.Index:
                    Match(DelphiTokens.Index);
                    TokenInfo Start = tokens[current];
                    return new IndexExternalOptionElement(Type, Expression(), GetComments());
            }
            return null;
        }

        /// <summary>
        /// Возможна директива external после имени процедуры/функции
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private ExternalDirectiveElement OptionalExternal()
        {
            if (MatchTokens(DelphiTokens.Semicolon) && MatchTokens(MatchAhead(), DelphiTokens.External))
            {
                Match(DelphiTokens.Semicolon);
                TokenInfo Type = tokens[current];
                Match(DelphiTokens.External);
                ExpressionElement name = null;
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Semicolon:
                    case DelphiTokens.Index:
                    case DelphiTokens.Name:
                        break;
                    default:
                        name = Expression();
                        break;
                }
                return new ExternalDirectiveElement(Type, name, OptionalExternalOption(), GetComments());
            }
            return null;
        }

        /// <summary>
        /// Возможны директивы экспорта после функции
        /// </summary>
        /// <returns>список директив</returns>
        private List<DirectiveElement> OptionalExportMod()
        {
            List<DirectiveElement> Exports = new List<DirectiveElement>();
            switch (tokens[current].Token)
            {
                case DelphiTokens.Export:
                case DelphiTokens.Local:
                    Exports.Add(new DirectiveElement(tokens[current], GetComments()));
                    Match(tokens[current].Token);
                    return Exports;
            }
            switch (MatchAhead())
            {
                case DelphiTokens.Export:
                case DelphiTokens.Local:
                    Match(DelphiTokens.Semicolon);
                    Exports.Add(new DirectiveElement(tokens[current], GetComments()));
                    Match(tokens[current].Token);
                    break;
            }
            return Exports;
        }

        /// <summary>
        /// Возможна директива message
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private MessageDirectiveElement OptionalMessage()
        {
            TokenInfo Type = tokens[current];
            if (tokens[current].Token == DelphiTokens.Message)
            {
                Match(DelphiTokens.Message);
                return new MessageDirectiveElement(Type, SimpleExpression(), GetComments());
            }
            else if (MatchAhead() == DelphiTokens.Message)
            {
                Match(DelphiTokens.Semicolon);
                Match(DelphiTokens.Message);
                return new MessageDirectiveElement(Type, SimpleExpression(), GetComments());
            }
            return null;
        }

        /// <summary>
        /// Возможны директивы после функции
        /// </summary>
        /// <returns>список директив</returns>
        private List<DirectiveElement> OptionalDirectives()
        {
            List<DirectiveElement> Directives = new List<DirectiveElement>();
            bool loop = true;
            while (loop)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Export:
                    case DelphiTokens.Local:
                    case DelphiTokens.Safecall:
                    case DelphiTokens.Stdcall:
                    case DelphiTokens.Forward:
                    case DelphiTokens.Far:
                    case DelphiTokens.Near:
                    case DelphiTokens.Reintroduce:
                    case DelphiTokens.Register:
                    case DelphiTokens.Cdecl:
                    case DelphiTokens.Varargs:
                    case DelphiTokens.Static:
                    case DelphiTokens.Virtual:
                    case DelphiTokens.Override:
                    case DelphiTokens.Abstract:
                    case DelphiTokens.Dynamic:
                    case DelphiTokens.Overload:
                    case DelphiTokens.Assembler:
                        Directives.Add(new DirectiveElement(tokens[current], GetComments()));
                        Match(tokens[current].Token);
                        continue;
                }
                switch (MatchAhead())
                {
                    case DelphiTokens.Export:
                    case DelphiTokens.Local:
                    case DelphiTokens.Safecall:
                    case DelphiTokens.Stdcall:
                    case DelphiTokens.Forward:
                    case DelphiTokens.Far:
                    case DelphiTokens.Near:
                    case DelphiTokens.Reintroduce:
                    case DelphiTokens.Register:
                    case DelphiTokens.Cdecl:
                    case DelphiTokens.Varargs:
                    case DelphiTokens.Static:
                    case DelphiTokens.Virtual:
                    case DelphiTokens.Override:
                    case DelphiTokens.Abstract:
                    case DelphiTokens.Dynamic:
                    case DelphiTokens.Overload:
                    case DelphiTokens.Assembler:
                        Match(DelphiTokens.Semicolon);
                        Directives.Add(new DirectiveElement(tokens[current], GetComments()));
                        Match(tokens[current].Token);
                        continue;
                }
                break;
            }
            Directives.AddRange(OptionalExportMod());
            Directives.AddNotNull(OptionalExternal());
            Directives.AddRange(OptionalExportMod());
            Directives.AddNotNull(OptionalMessage());
            Directives.AddRange(OptionalExportMod());
            return Directives;
        }

        /// <summary>
        /// Булевое значение
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private ConstExpressionElement Bool()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.True:
                case DelphiTokens.False:
                    List<TokenInfo> Bool = new List<TokenInfo>();
                    Bool.Add(tokens[current]);
                    Match(tokens[current].Token);
                    return new ConstExpressionElement(Bool[0], Bool, GetComments());
                default:
                    Panic();
                    return null;
            }
        }

        /// <summary>
        /// Вообще после любой переменной может идти многократное разыменования (если это указатель на указатель)
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private CaretsElement OptionalCarets()
        {
            int count = 0;
            TokenInfo Start = tokens[current];
            while (MatchTokens(DelphiTokens.Caret))
            {
                Match(DelphiTokens.Caret);
                count++;
            }
            if (count > 0) return new CaretsElement(Start, count, GetComments());
            else return null;
        }

        /// <summary>
        /// Возможен индекс после имени переменной (если она массив)
        /// </summary>
        /// <returns>список блоков</returns>
        private List<BlockOfPartOfStandartVariableExpressionElement> OptionalArrayIndex()
        {
            List<BlockOfPartOfStandartVariableExpressionElement> Blocks = new List<BlockOfPartOfStandartVariableExpressionElement>();
            TokenInfo Start;
            while (MatchTokens(DelphiTokens.LSBr))
            {
                Start = tokens[current];
                Match(DelphiTokens.LSBr);
                ArrayIndexElement ArrayIndex = new ArrayIndexElement(Start, OptionalExpressionList(), GetComments());
                if (ArrayIndex != null)
                    Blocks.Add(ArrayIndex);
                Match(DelphiTokens.RSBr);
                CaretsElement Carets = OptionalCarets();
                if (Carets != null)
                    Blocks.Add(Carets);
                Blocks.AddRange(OptionalFunctionParams());
            }
            return Blocks;
        }

        /// <summary>
        /// Возможны параметры после имени переменной (если она функция/процедура)
        /// </summary>
        /// <returns>список блоков</returns>
        private List<BlockOfPartOfStandartVariableExpressionElement> OptionalFunctionParams()
        {
            List<BlockOfPartOfStandartVariableExpressionElement> Blocks = new List<BlockOfPartOfStandartVariableExpressionElement>();
            while (MatchTokens(DelphiTokens.LBr))
            {
                Match(DelphiTokens.LBr);
                if (!MatchTokens(DelphiTokens.RBr))
                    Blocks.Add(AssignmentParams());
                Match(DelphiTokens.RBr);
                CaretsElement Carets = OptionalCarets();
                if (Carets != null)
                    Blocks.Add(Carets);
                Blocks.AddRange(OptionalArrayIndex());
            }
            return Blocks;
        }

        /// <summary>
        /// После имени переменной может идти любая последовательность () [] ^
        /// </summary>
        /// <returns>список блоков</returns>
        private List<BlockOfPartOfStandartVariableExpressionElement> OptionalAFExtension()
        {
            List<BlockOfPartOfStandartVariableExpressionElement> Blocks = new List<BlockOfPartOfStandartVariableExpressionElement>();
            CaretsElement Carets = OptionalCarets();
            if (Carets != null)
                Blocks.Add(Carets);
            switch (tokens[current].Token)
            {
                case DelphiTokens.LSBr:
                    Blocks.AddRange(OptionalArrayIndex());
                    break;
                case DelphiTokens.LBr:
                    Blocks.AddRange(OptionalFunctionParams());
                    break;
            }
            return Blocks;
        }

        /// <summary>
        /// Возможно округление значения (x:2)
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private RoundElement OptionalRealRounded()
        {
            if (MatchTokens(DelphiTokens.Colon))
            {
                TokenInfo Start = tokens[current];
                Match(DelphiTokens.Colon);
                return new RoundElement(Start, SimpleExpression(), GetComments());
            }
            else return null;
        }

        /// <summary>
        /// Параметр может быть задан в виде присвоения (What:=x)
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private AssignmentParamElement AssignmentParam()
        {
            if (MatchTokens(MatchAhead(), DelphiTokens.Assignment))
            {
                TokenInfo Id = tokens[current];
                Match(DelphiTokens.Id);
                Match(DelphiTokens.Assignment);
                return new AssignmentParamElement(Id, Id, Expression(), null, null, GetComments());
            }
            else return new AssignmentParamElement(tokens[current], null, Expression(), OptionalRealRounded(), OptionalRealRounded(), GetComments());
        }

        /// <summary>
        /// Набор параметров типа присваивания
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private AssignmentParamsElement AssignmentParams()
        {
            List<AssignmentParamElement> AssignmentParams = new List<AssignmentParamElement>();
            TokenInfo Start = tokens[current];
            AssignmentParams.Add(AssignmentParam());
            while (MatchTokens(DelphiTokens.Comma))
            {
                Match(DelphiTokens.Comma);
                AssignmentParams.Add(AssignmentParam());
            }
            return new AssignmentParamsElement(Start, AssignmentParams, GetComments());
        }

        /// <summary>
        /// Операнд-переменная
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private VariableExpressionElement Variable()
        {
            ExpressionElement Source = null;
            List<PartOfStandartVariableExpressionElement> Parts = new List<PartOfStandartVariableExpressionElement>();
            TokenInfo Token, Start = tokens[current];
            bool loop = true;
            switch (tokens[current].Token)
            {
                case DelphiTokens.LBr:
                    Match(DelphiTokens.LBr);
                    Source = Expression();
                    Match(DelphiTokens.RBr);
                    loop = MatchTokens(DelphiTokens.Dot);
                    if (loop) Match(DelphiTokens.Dot);
                    break;
                case DelphiTokens.LSBr:
                    IntervalsVariableExpressionElement Intervals = null;
                    Match(DelphiTokens.LSBr);
                    if (!MatchTokens(DelphiTokens.RSBr))
                        Intervals = this.Intervals();
                    else Intervals = new IntervalsVariableExpressionElement(Start, null, GetComments());
                    Match(DelphiTokens.RSBr);
                    loop = false;
                    return Intervals;
                case DelphiTokens.AtSign:
                    Match(DelphiTokens.AtSign);
                    return new PointerToVariableExpressionElement(Start, Variable(), GetComments());
            }
            while (loop)
            {
                Token = tokens[current];
                ExtraMatch();
                Parts.Add(new PartOfStandartVariableExpressionElement(Token, Token, OptionalAFExtension(), GetComments()));
                if (MatchTokens(DelphiTokens.Dot))
                    Match(DelphiTokens.Dot);
                else return new StandartVariableExpressionElement(Start, Source, Parts, GetComments());
            }
            return new StandartVariableExpressionElement(Start, Source, Parts, GetComments());
        }

        /// <summary>
        /// Наивысший приоритет операций (скобки перенесены на уровень переменных в связи с (TObject as TButton).Caption)
        /// </summary>
        /// <returns>соответствующий элемент-выражение</returns>
        private ExpressionElement Factor()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.Not:
                case DelphiTokens.AtSign:
                case DelphiTokens.Inherited:
                case DelphiTokens.Addition:
                case DelphiTokens.Subtraction:
                    TokenInfo Type = tokens[current];
                    Match(tokens[current].Token);
                    return new UnaryExpressionElement(Type, Factor(), GetComments());
                case DelphiTokens.String:
                case DelphiTokens.Char:
                case DelphiTokens.Digits:
                case DelphiTokens.HexConstant:
                case DelphiTokens.Real:
                case DelphiTokens.Exponent:
                case DelphiTokens.True:
                case DelphiTokens.False:
                    return Const();
                default:
                    return Variable();
            }
        }

        /// <summary>
        /// Высокий приоритет
        /// </summary>
        /// <returns>соответствующий элемент-выражение</returns>
        private ExpressionElement Term()
        {
            TokenInfo Type;
            ExpressionElement Expr = Factor();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Multiply:
                    case DelphiTokens.Division:
                    case DelphiTokens.Div:
                    case DelphiTokens.Mod:
                    case DelphiTokens.And:
                    case DelphiTokens.Shl:
                    case DelphiTokens.Shr:
                        Type = tokens[current];
                        Match(tokens[current].Token);
                        Expr = new BinaryExpressionElement(Type, Expr, Factor(), GetComments());
                        break;
                    case DelphiTokens.Caret:
                        Type = tokens[current];
                        Match( DelphiTokens.Caret);
                        Expr = new IndirectionUnaryExpressionElement(Type, Expr, GetComments());
                        break;
                    default:
                        return Expr;
                }
            }
        }

        /// <summary>
        /// Низкий приоритет
        /// </summary>
        /// <returns>соответствующий элемент-выражение</returns>
        private ExpressionElement SimpleExpression()
        {
            TokenInfo Type;
            ExpressionElement Expr = Term();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Addition:
                    case DelphiTokens.Subtraction:
                    case DelphiTokens.Or:
                    case DelphiTokens.Xor:
                        Type = tokens[current];
                        Match(tokens[current].Token);
                        Expr = new BinaryExpressionElement(Type, Expr, Term(), GetComments());
                        break;
                    default:
                        return Expr;
                }
            }
        }

        /// <summary>
        /// Самый низкий приоритет
        /// </summary>
        /// <returns>соответствующий элемент-выражение</returns>
        private ExpressionElement Expression()
        {
            TokenInfo Type;
            ExpressionElement Expr = SimpleExpression();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Equal:
                    case DelphiTokens.Less:
                    case DelphiTokens.Greater:
                    case DelphiTokens.LessOrEqual:
                    case DelphiTokens.GreaterOrEqual:
                    case DelphiTokens.NotEqual:
                    case DelphiTokens.In:
                    case DelphiTokens.Is:
                    case DelphiTokens.As:
                        Type = tokens[current];
                        Match(tokens[current].Token);
                        Expr = new BinaryExpressionElement(Type, Expr, SimpleExpression(), GetComments());
                        break;
                    default:
                        return Expr;
                }
            }
        }

        /// <summary>
        /// Список выражений
        /// </summary>
        /// <returns>список выражений</returns>
        private List<ExpressionElement> ExpressionList()
        {
            List<ExpressionElement> Expressions = new List<ExpressionElement>();
            Expressions.Add(Expression());
            while (MatchTokens(DelphiTokens.Comma))
            {
                Match(DelphiTokens.Comma);
                Expressions.Add(Expression());
            }
            return Expressions;
        }

        /// <summary>
        /// Возможен список выражений
        /// </summary>
        /// <returns>список выражений</returns>
        private List<ExpressionElement> OptionalExpressionList()
        {
            List<ExpressionElement> Expressions = new List<ExpressionElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Addition:
                    case DelphiTokens.Subtraction:
                    case DelphiTokens.Digits:
                    case DelphiTokens.HexConstant:
                    case DelphiTokens.Char:
                    case DelphiTokens.String:
                    case DelphiTokens.LBr:
                    case DelphiTokens.LSBr:
                    case DelphiTokens.AtSign:
                    case DelphiTokens.Not:
                    case DelphiTokens.True:
                    case DelphiTokens.False:
                    case DelphiTokens.Inherited:
                        Expressions.Add(Expression());
                        break;
                    case DelphiTokens.Comma:
                        Match(DelphiTokens.Comma);
                        Expressions.Add(Expression());
                        break;
                    default:
                        if (MatchTokens(DelphiTokens.Id))
                            Expressions.Add(Expression());
                        else return Expressions;
                        break;
                }
            }
        }

        /// <summary>
        /// Возможен список переменных в заголовке функции/процедуры
        /// </summary>
        /// <returns>список объявлений</returns>
        private List<FunctionVarDeclarationElement> OptionalVars()
        {
            List<FunctionVarDeclarationElement> Vars = null;
            if (MatchTokens(DelphiTokens.LBr))
            {
                Match(DelphiTokens.LBr);
                if (!MatchTokens(DelphiTokens.RBr))
                    Vars = FunctionVariableDeclarations();
                Match(DelphiTokens.RBr);
            }
            return Vars;
        }

        /// <summary>
        /// Функциональный тип может иметь расширение of object
        /// </summary>
        /// <returns>есть ли расширение of object</returns>
        private bool OptionalOfObject()
        {
            if (MatchTokens(DelphiTokens.Of))
            {
                Match(DelphiTokens.Of);
                Match(DelphiTokens.Object);
                return true;
            }
            else return false;
        }

        /// <summary>
        /// Контракт процедурного типа
        /// </summary>
        /// <returns>соответствующий элемент-контракт процедуры</returns>
        private ProcedureTypeElement TypeProcedureContract()
        {
            TokenInfo Type = tokens[current];
            Match(DelphiTokens.Procedure);
            return new ProcedureTypeElement(Type, OptionalVars(), OptionalOfObject(), OptionalDirectives(), GetComments());
        }

        /// <summary>
        /// Контракт функционального типа
        /// </summary>
        /// <returns>соответствующий элемент-тип функции</returns>
        private FunctionTypeElement TypeFunctionContract()
        {
            TokenInfo Type = tokens[current];
            Match(DelphiTokens.Function);
            List<FunctionVarDeclarationElement> Vars = OptionalVars();
            Match(DelphiTokens.Colon);
            return new FunctionTypeElement(Type, Vars, SimpleType(), OptionalOfObject(), OptionalDirectives(), GetComments());
        }

        /// <summary>
        /// Заголовок процедуры
        /// </summary>
        /// <returns>соответствующий элемент-заголовок процедуры</returns>
        private InnerProcedureHeadElement InnerProcedureHead()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.Constructor:
                case DelphiTokens.Destructor:
                case DelphiTokens.Procedure:
                    TokenInfo Type = tokens[current];
                    Match(tokens[current].Token);
                    TokenInfo Name = tokens[current];
                    Match(DelphiTokens.Id);
                    InnerProcedureHeadElement Result = new InnerProcedureHeadElement(Type, Name, OptionalVars(), OptionalDirectives(), GetComments());
                    Match(DelphiTokens.Semicolon);
                    return Result;
                default:
                    Panic();
                    break;
            }
            return null;
        }

        /// <summary>
        /// Заголовок процедуры dispatch-интерфейса
        /// </summary>
        /// <returns>соответствующий элемент-заголовок процедуры</returns>
        private DispinterfaceProcedureHeadElement DispinterfaceProcedureHead()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.Constructor:
                case DelphiTokens.Destructor:
                case DelphiTokens.Procedure:
                    TokenInfo Type = tokens[current];
                    Match(tokens[current].Token);
                    TokenInfo Name = tokens[current];
                    Match(DelphiTokens.Id);
                    DispinterfaceProcedureHeadElement Result = new DispinterfaceProcedureHeadElement(Type, Name, OptionalVars(), OptionalDirectives(), null, GetComments());
                    Match(DelphiTokens.Semicolon);
                    PropertyOptionElement dispid = OptionalDispid();
                    if (dispid != null)
                    {
                        Result.Dispid = dispid;
                        Match(DelphiTokens.Semicolon);
                    }
                    return Result;
                default:
                    Panic();
                    break;
            }
            return null;
        }

        /// <summary>
        /// Заголовок функции
        /// </summary>
        /// <returns>соответствующий элемент-заголовок функции</returns>
        private InnerFunctionHeadElement InnerFunctionHead()
        {
            bool ClassMethod = OptionalClassMethod();
            TokenInfo Type = tokens[current];
            Match(DelphiTokens.Function);
            TokenInfo Name = tokens[current];
            Match(DelphiTokens.Id);
            List<FunctionVarDeclarationElement> Vars = OptionalVars();
            ITypeElement ResultType = null;
            bool typedefined = MatchTokens(DelphiTokens.Colon);
            if (typedefined)
            {
                Match(DelphiTokens.Colon);
                ResultType = SimpleType();
            }
            InnerFunctionHeadElement Result = (ClassMethod) ?
                new InnerRecordClassMethodElement(Type, Name, Vars, OptionalDirectives(), ResultType, GetComments()) :
                new InnerFunctionHeadElement(Type, Name, Vars, OptionalDirectives(), ResultType, GetComments());
            Match(DelphiTokens.Semicolon);
            return Result;
        }

        /// <summary>
        /// Заголовок функции dispatch-интерфейса
        /// </summary>
        /// <returns>соответствующий элемент-заголовок функции</returns>
        private DispinterfaceFunctionHeadElement DispinterfaceFunctionHead()
        {
            TokenInfo Type = tokens[current];
            Match(DelphiTokens.Function);
            TokenInfo Name = tokens[current];
            Match(DelphiTokens.Id);
            List<FunctionVarDeclarationElement> Vars = OptionalVars();
            ITypeElement ResultType = null;
            if (MatchTokens(DelphiTokens.Colon))
            {
                Match(DelphiTokens.Colon);
                ResultType = SimpleType();
            }
            DispinterfaceFunctionHeadElement Result = new DispinterfaceFunctionHeadElement(Type, Name, Vars, OptionalDirectives(), ResultType, null, GetComments());
            Match(DelphiTokens.Semicolon);
            PropertyOptionElement dispid = OptionalDispid();
            if (dispid != null)
            {
                Result.Dispid = dispid;
                Match(DelphiTokens.Semicolon);
            }
            return Result;
        }

        /// <summary>
        /// Заголовок процедуры (если класса, то вне его)
        /// </summary>
        /// <returns>соответствующий элемент-заголовок процедуры</returns>
        private OuterProcedureHeadElement OuterProcedureHead()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.Constructor:
                case DelphiTokens.Destructor:
                case DelphiTokens.Procedure:
                    TokenInfo Type = tokens[current];
                    Match(tokens[current].Token);
                    IdElement ClassName = null,
                        Name = new IdElement(tokens[current], GetComments());
                    Match(DelphiTokens.Id);
                    if (MatchTokens(DelphiTokens.Dot))
                    {
                        Match(DelphiTokens.Dot);
                        ClassName = Name;
                        Name = new IdElement(tokens[current], GetComments());
                        Match(DelphiTokens.Id);
                    }
                    List<TokenInfo> Comments = List<TokenInfo>.Combine(GetComments(), Name.Comments);
                    OuterProcedureHeadElement Result = new OuterProcedureHeadElement(Type, ClassName, Name.Id, OptionalVars(), OptionalDirectives(), Comments);
                    Match(DelphiTokens.Semicolon);
                    return Result;
                default:
                    Panic();
                    return null;
            }
        }

        /// <summary>
        /// Заголовок функции
        /// </summary>
        /// <returns>соответствующий элемент-заголовок функции</returns>
        private OuterFunctionHeadElement OuterFunctionHead()
        {
            bool ClassMethod = OptionalClassMethod();
            TokenInfo Type = tokens[current];
            Match(DelphiTokens.Function);
            IdElement ClassName = null,
                Name = new IdElement(tokens[current], GetComments());
            Match(DelphiTokens.Id);
            if (MatchTokens(DelphiTokens.Dot))
            {
                Match(DelphiTokens.Dot);
                ClassName = Name;
                Name = new IdElement(tokens[current], GetComments());
                Match(DelphiTokens.Id);
            }
            List<FunctionVarDeclarationElement> Vars = OptionalVars();
            ITypeElement ResultType = null;
            bool typedefined = MatchTokens(DelphiTokens.Colon);
            if (typedefined)
            {
                Match(DelphiTokens.Colon);
                ResultType = SimpleType();
            }
            List<TokenInfo> Comments = List<TokenInfo>.Combine(GetComments(), Name.Comments);
            OuterFunctionHeadElement Result = (ClassMethod) ?
                new OuterRecordClassMethodElement(Type, ClassName, Name.Id, Vars, OptionalDirectives(), ResultType, GetComments()) :
                new OuterFunctionHeadElement(Type, ClassName, Name.Id, Vars, OptionalDirectives(), ResultType, GetComments());
            Match(DelphiTokens.Semicolon);
            return Result;
        }

        /// <summary>
        /// Возможен метод класса (директива class)
        /// </summary>
        /// <returns>является методом класса</returns>
        private bool OptionalClassMethod()
        {
            if (MatchTokens(DelphiTokens.Class))
            {
                Match(DelphiTokens.Class);
                return true;
            }
            else return false;
        }

        /// <summary>
        /// Хаголовок метода класса
        /// </summary>
        /// <returns>соответствующий элемент-метод класса</returns>
        private ClassMethodElement InnerClassMethod()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Class);
            switch (tokens[current].Token)
            {
                case DelphiTokens.Procedure:
                    return new ClassMethodElement(Start, InnerProcedureHead(), GetComments());
                case DelphiTokens.Function:
                    return new ClassMethodElement(Start, InnerFunctionHead(), GetComments());
                default:
                    Panic();
                    return null;
            }
        }

        /// <summary>
        /// Внешний заголовок метода класса
        /// </summary>
        /// <returns>соответствующий элемент-метод класса</returns>
        private ClassMethodElement OuterClassMethod()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Class);
            switch (tokens[current].Token)
            {
                case DelphiTokens.Procedure:
                    return new ClassMethodElement(Start, OuterProcedureHead(), GetComments());
                case DelphiTokens.Function:
                    return new ClassMethodElement(Start, OuterFunctionHead(), GetComments());
                    break;
                default:
                    Panic();
                    return null;
            }
        }

        /// <summary>
        /// Интервал значений
        /// </summary>
        /// <returns>соответствующий элемент-интервал</returns>
        private IntervalVariableExpressionElement Interval()
        {
            ExpressionElement Start = SimpleExpression();
            ExpressionElement End = null;
            if (MatchTokens(DelphiTokens.Interval))
            {
                Match(DelphiTokens.Interval);
                End = SimpleExpression();
            }
            return new IntervalVariableExpressionElement(Start.StartInfo, Start, End, GetComments());
        }

        /// <summary>
        /// Несколько интервалов
        /// </summary>
        /// <returns>соответствующий элемент-интервалы</returns>
        private IntervalsVariableExpressionElement Intervals()
        {
            List<IntervalVariableExpressionElement> Intervals = new List<IntervalVariableExpressionElement>();
            TokenInfo Start = tokens[current];
            Intervals.Add(Interval());
            while (MatchTokens(DelphiTokens.Comma))
            {
                Match(DelphiTokens.Comma);
                Intervals.Add(Interval());
            }
            return new IntervalsVariableExpressionElement(Start, Intervals, GetComments());
        }

        /// <summary>
        /// Возможен интервал значений
        /// </summary>
        /// <returns>соответствующий элемент-интервалы</returns>
        private IntervalsVariableExpressionElement OptionalIntervals()
        {
            if (MatchTokens(DelphiTokens.LSBr))
            {
                Match(DelphiTokens.LSBr);
                IntervalsVariableExpressionElement Intervals = this.Intervals();
                Match(DelphiTokens.RSBr);
                return Intervals;
            }
            else return null;
        }

        /// <summary>
        /// Тип возвращаемого функцией значения
        /// </summary>
        /// <returns>соответствующий элемент-тип</returns>
        private ITypeElement FunctionTypeDefinition()
        {
            TokenInfo Start = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Array:
                    Match(DelphiTokens.Array);
                    Match(DelphiTokens.Of);
                    return new ArrayTypeElement(Start, null, SimpleType(), GetComments());
                default:
                    return new IntervalCommonTypeElement(Start, Interval(), GetComments());
            }
        }

        /// <summary>
        /// Тип - указатель на тип
        /// </summary>
        /// <returns>соответствующий элемент-указатель</returns>
        private PointerSimpleTypeElement PointerType()
        {
            Match(DelphiTokens.Caret);
            TokenInfo Id = tokens[current];
            Match(DelphiTokens.Id);
            return new PointerSimpleTypeElement(Id, GetComments());
        }

        /// <summary>
        /// Тип набор, каждый элемент которого может иметь числовое значение
        /// </summary>
        /// <returns>соответствующий элемент-элемент перечисления</returns>
        private ObjectEnumCommonTypeElement SimpleTypeObject()
        {
            TokenInfo Id = tokens[current];
            Match(DelphiTokens.Id);
            if (MatchTokens(DelphiTokens.Equal))
            {
                Match(DelphiTokens.Equal);
                return new ObjectEnumCommonTypeElement(Id, SignedInt(), GetComments());
            }
            else return new ObjectEnumCommonTypeElement(Id, null, GetComments());
        }

        /// <summary>
        /// Простой тип - перечислымый
        /// </summary>
        /// <returns>соответствующий элемент-простой тип</returns>
        private ICommonTypeElement SimpleType()
        {
            TokenInfo Start = tokens[current];
            if (MatchTokens(DelphiTokens.LBr))
            {
                List<ObjectEnumCommonTypeElement> Elements = new List<ObjectEnumCommonTypeElement>();
                Match(DelphiTokens.LBr);
                Elements.Add(SimpleTypeObject());
                while (MatchTokens(DelphiTokens.Comma))
                {
                    Match(DelphiTokens.Comma);
                    Elements.Add(SimpleTypeObject());
                }
                Match(DelphiTokens.RBr);
                return new EnumCommonTypeElement(Start, Elements, GetComments());
            }
            else return new IntervalCommonTypeElement(Start, Interval(), GetComments());
        }

        /// <summary>
        /// Объявление типа set
        /// </summary>
        /// <returns>соответствующий элемент-простой тип набор</returns>
        private SetCommonTypeElement SetDefinition()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Set);
            Match(DelphiTokens.Of);
            return new SetCommonTypeElement(Start, SimpleType(), GetComments());
        }

        /// <summary>
        /// Объявления типа file
        /// </summary>
        /// <returns>соответствующий элемент-файловый тип</returns>
        private FileTypeElement FileDefinition()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.File);
            if (MatchTokens(DelphiTokens.Of))
            {
                Match(DelphiTokens.Of);
                return new FileTypeElement(Start, SimpleType(), GetComments());
            }
            else return new FileTypeElement(Start, GetComments());
        }

        /// <summary>
        /// Объявление простых константных типов (все локальные типы кроме массива)
        /// </summary>
        /// <returns>соответствующий элемент-простой константный тип</returns>
        private ISimpleConstTypeElement SimpleConstTypeDefinition()
        {
            TokenInfo Start = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.LBr:
                    return SimpleType();
                case DelphiTokens.Record:
                    return ConstRecordDefinition();
                case DelphiTokens.Set:
                    return SetDefinition();
                case DelphiTokens.Packed:
                    Match(DelphiTokens.Packed);
                    IConstTypeElement Type = null;
                    switch (tokens[current].Token)
                    {
                        case DelphiTokens.Record:
                            Type = ConstRecordDefinition();
                            break;
                        case DelphiTokens.Set:
                            Type = SetDefinition();
                            break;
                        default:
                            Panic();
                            break;
                    }
                    return new PackedConstTypeElement(Start, Type, GetComments());
                    break;
                default:
                    return new IntervalCommonTypeElement(Start, Interval(), GetComments());
            }
        }

        /// <summary>
        /// Объявление константных типов
        /// </summary>
        /// <returns>соответствующий элемент-константный тип</returns>
        private IConstTypeElement ConstTypeDefinition()
        {
            TokenInfo Start = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Array:
                    Match(DelphiTokens.Array);
                    Match(DelphiTokens.LSBr);
                    IntervalsVariableExpressionElement Intervals = this.Intervals();
                    Match(DelphiTokens.RSBr);
                    Match(DelphiTokens.Of);
                    return new ArrayConstTypeElement(Start, Intervals, ConstTypeDefinition(), GetComments());
                case DelphiTokens.Packed:
                    Match(DelphiTokens.Packed);
                    IConstTypeElement Type;
                    switch (tokens[current].Token)
                    {
                        case DelphiTokens.Array:
                            TokenInfo AStart = tokens[current];
                            Match(DelphiTokens.Array);
                            Match(DelphiTokens.LSBr);
                            Intervals = this.Intervals();
                            Match(DelphiTokens.RSBr);
                            Match(DelphiTokens.Of);
                            Type = new ArrayConstTypeElement(AStart, Intervals, ConstTypeDefinition(), GetComments());
                            break;
                        default:
                            Type = SimpleConstTypeDefinition();
                            break;
                    }
                    return new PackedConstTypeElement(Start, Type, GetComments());
                default:
                    return SimpleConstTypeDefinition();
            }
        }

        /// <summary>
        /// Объявления типа ссылки на метод
        /// </summary>
        /// <returns>соответствующий элемент-ссылка на метод</returns>
        private ReferenceTypeElement ReferenceDefinition()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Reference);
            Match(DelphiTokens.To);
            switch (tokens[current].Token)
            {
                case DelphiTokens.Procedure:
                    return new ReferenceTypeElement(Start, TypeProcedureContract(), GetComments());
                case DelphiTokens.Function:
                    return new ReferenceTypeElement(Start, TypeFunctionContract(), GetComments());
            }
            return null;
        }

        /// <summary>
        /// Объявление простых типов
        /// </summary>
        /// <returns>соответствующий элемент-простой тип</returns>
        private ITypeElement SimpleTypeDefinition()
        {
            TokenInfo Start = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Caret:
                    return PointerType();
                case DelphiTokens.LBr:
                    return SimpleType();
                case DelphiTokens.Record:
                    return RecordDefinition();
                case DelphiTokens.Set:
                    return SetDefinition();
                case DelphiTokens.File:
                    return FileDefinition();
                case DelphiTokens.Procedure:
                    return TypeProcedureContract();
                case DelphiTokens.Function:
                    return TypeFunctionContract();
                case DelphiTokens.Reference:
                    return ReferenceDefinition();
                case DelphiTokens.Packed:
                    ITypeElement Type = null;
                    Match(DelphiTokens.Packed);
                    switch (tokens[current].Token)
                    {
                        case DelphiTokens.Record:
                            Type = RecordDefinition();
                            break;
                        case DelphiTokens.Set:
                            Type = SetDefinition();
                            break;
                        case DelphiTokens.File:
                            Type = FileDefinition();
                            break;
                    }
                    return new PackedTypeElement(Start, Type, GetComments());
                default:
                    return new IntervalCommonTypeElement(Start, Interval(), GetComments());
            }
            return null;
        }

        /// <summary>
        /// Объявление типов
        /// </summary>
        /// <returns>соответствующий элемент-тип</returns>
        private ITypeElement TypeDefinition()
        {
            TokenInfo Start = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Array:
                    Match(DelphiTokens.Array);
                    IntervalsVariableExpressionElement Intervals = OptionalIntervals();
                    Match(DelphiTokens.Of);
                    return new ArrayTypeElement(Start, Intervals, TypeDefinition(), GetComments());
                case DelphiTokens.Packed:
                    Match(DelphiTokens.Packed);
                    ITypeElement Type;
                    switch (tokens[current].Token)
                    {
                        case DelphiTokens.Array:
                            Match(DelphiTokens.Array);
                            Intervals = OptionalIntervals();
                            Match(DelphiTokens.Of);
                            Type = TypeDefinition();
                            break;
                        default:
                            Type = SimpleTypeDefinition();
                            break;
                    }
                    return new PackedTypeElement(Start, Type, GetComments());
                default:
                    return SimpleTypeDefinition();
            }
        }

        /// <summary>
        /// Список идентификаторов
        /// </summary>
        /// <returns>список идентификаторов</returns>
        private List<IdElement> IdList()
        {
            List<IdElement> ids = new List<IdElement>();
            ids.Add(new IdElement(tokens[current], GetComments()));
            Match(DelphiTokens.Id);
            while (MatchTokens(DelphiTokens.Comma))
            {
                Match(DelphiTokens.Comma);
                ids.Add(new IdElement(tokens[current], GetComments()));
                Match(DelphiTokens.Id);
            }
            return ids;
        }

        /// <summary>
        /// Возможен префикс (int, out, const, var)
        /// </summary>
        /// <returns>токен-префикс</returns>
        private TokenInfo OptionalPrefix()
        {
            TokenInfo Prefix = null;
            switch (tokens[current].Token)
            {
                case DelphiTokens.In:
                case DelphiTokens.Out:
                case DelphiTokens.Var:
                case DelphiTokens.Const:
                    Prefix = tokens[current];
                    Match(tokens[current].Token);
                    break;
            }
            return Prefix;
        }

        /// <summary>
        /// Возможна директива absolute
        /// </summary>
        /// <returns>идентификатор, если директива присутствует</returns>
        private IdElement OptionalAbsolute()
        {
            if (MatchTokens(DelphiTokens.Absolute))
            {
                Match(DelphiTokens.Absolute);
                IdElement Id = new IdElement(tokens[current], GetComments());
                Match(DelphiTokens.Id);
                return Id;
            }
            else return null;
        }

        /// <summary>
        /// Объявление локальных переменных в функции
        /// </summary>
        /// <returns>соответствующий элемент-объявление переменных</returns>
        private FunctionVarDeclarationElement FunctionVariableDeclaration()
        {
            List<IdElement> Ids = IdList();
            bool many = (Ids.Count > 1);
            ITypeElement Type = null;
            ExpressionElement Value = null;
            if (MatchTokens(DelphiTokens.Colon))
            {
                Match(DelphiTokens.Colon);
                Type = FunctionTypeDefinition();
            }
            bool platform = MatchTokens(DelphiTokens.Platform);
            if (platform)
                Match(DelphiTokens.Platform);
            if (!many && MatchTokens(DelphiTokens.Equal))
            {
                Match(DelphiTokens.Equal);
                Value = Expression();
            }
            return new FunctionVarDeclarationElement(Ids[0].StartInfo, Ids, Type, platform, Value, GetComments());
        }

        /// <summary>
        /// Объявления локальных переменных в функции
        /// </summary>
        /// <returns>список объявлений локальных переменных</returns>
        private List<FunctionVarDeclarationElement> FunctionVariableDeclarations()
        {
            List<FunctionVarDeclarationElement> Vars = new List<FunctionVarDeclarationElement>();
            TokenInfo Prefix = OptionalPrefix();
            if (Prefix != null)
                Vars.Add(new PrefixedFunctionVarDeclarationElement(Prefix, FunctionVariableDeclaration(), GetComments()));
            else Vars.Add(FunctionVariableDeclaration());
            while (MatchTokens(DelphiTokens.Semicolon))
            {
                Match(DelphiTokens.Semicolon);
                Prefix = OptionalPrefix();
                if (Prefix != null)
                    Vars.Add(new PrefixedFunctionVarDeclarationElement(Prefix, FunctionVariableDeclaration(), GetComments()));
                else Vars.Add(FunctionVariableDeclaration());
            }
            return Vars;
        }

        /// <summary>
        /// Объявление переменных
        /// </summary>
        /// <param name="NeedSemicolon">обязателен ли знак ";" после объявления</param>
        /// <param name="IsStatic">являются ли переменные статическими</param>
        /// <returns>соответствующий элемент-объявление переменных</returns>
        private VarDeclarationElement VarDeclaration(bool NeedSemicolon)
        {
            List<IdElement> Ids = IdList();
            bool many = (Ids.Count > 1);
            Match(DelphiTokens.Colon);
            ITypeElement Type = TypeDefinition();
            bool platform = MatchTokens(DelphiTokens.Platform);
            if (platform)
                Match(DelphiTokens.Platform);
            ISyntaxTreeElement Value = null;
            IdElement Absolute = null;
            if (!many && MatchTokens(DelphiTokens.Equal))
            {
                Match(DelphiTokens.Equal);
                Value = ConstValue();
            }
            else Absolute = OptionalAbsolute();
            if (NeedSemicolon) Match(DelphiTokens.Semicolon);
            else OptionalSemicolon();
            return new VarDeclarationElement(Ids[0].StartInfo, Ids, Type, platform, Value, Absolute, GetComments());
        }

        /// <summary>
        /// Объявление переменных
        /// </summary>
        /// <returns>соответствующий элемент-объявление переменных</returns>
        private VarDeclarationElement VarDeclaration()
        {
            return VarDeclaration(true);
        }

        /// <summary>
        /// Объявления переменных
        /// </summary>
        /// <param name="NeedSemicolon">обязателен ли знак ";" в конце блока объявлений</param>
        /// <returns>список объявлений переменных</returns>
        private List<VarDeclarationElement> VarDeclarations(bool NeedSemicolon)
        {
            List<VarDeclarationElement> Vars = new List<VarDeclarationElement>();
            Vars.Add(VarDeclaration(NeedSemicolon));
            while (MatchTokens(DelphiTokens.Id))
                Vars.Add(VarDeclaration(NeedSemicolon));
            return Vars;
        }

        /// <summary>
        /// Объявления переменных
        /// </summary>
        /// <returns>список объявлений переменных</returns>
        private List<VarDeclarationElement> VarDeclarations()
        {
            return VarDeclarations(true);
        }

        /// <summary>
        /// Возможен символ ";"
        /// </summary>
        private void OptionalSemicolon()
        {
            if (MatchTokens(DelphiTokens.Semicolon))
                Match(DelphiTokens.Semicolon);
        }

        /// <summary>
        /// Блок кода (begin ... end)
        /// </summary>
        /// <returns>соответствующий элемент-блок кода</returns>
        private CompoundStatementElement CompoundStatement()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Begin);
            CompoundStatementElement Compound = new CompoundStatementElement(Start, OptionalStatements(), GetComments());
            Match(DelphiTokens.End);
            return Compound;
        }

        /// <summary>
        /// Возможен else
        /// </summary>
        /// <returns>соответствующий элемент-оператор</returns>
        private StatementElement OptionalElse()
        {
            if (MatchTokens(DelphiTokens.Else))
            {
                TokenInfo Start = tokens[current];
                Match(DelphiTokens.Else);
                return new ElseStatementElement(Start, Statement(false), GetComments());
            }
            else return null;
        }

        /// <summary>
        /// Возможен идентификатор в блоке on ... do ...
        /// </summary>
        /// <returns>соответствующий элемент-идентификатор</returns>
        private IdElement OptionalId()
        {
            if (MatchTokens(MatchAhead(), DelphiTokens.Colon))
            {
                IdElement Id = new IdElement(tokens[current], GetComments());
                Match(DelphiTokens.Id);
                Match(DelphiTokens.Colon);
                return Id;
            }
            else return null;
        }

        /// <summary>
        /// Блок после try (finally или except)
        /// </summary>
        /// <returns>соответствующий элемент-оператор</returns>
        private StatementElement TryOptionBlock()
        {
            TokenInfo Start = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Except:
                    Match(DelphiTokens.Except);
                    TokenInfo SStart = tokens[current], EStart;
                    switch (tokens[current].Token)
                    {
                        case DelphiTokens.On:
                            List<StatementElement> Statements = new List<StatementElement>();
                            IdElement Id, Type;
                            while (MatchTokens(DelphiTokens.On))
                            {
                                EStart = tokens[current];
                                Match(DelphiTokens.On);
                                Id = OptionalId();
                                if (Id == null)
                                {
                                    Id = new IdElement(tokens[current], GetComments());
                                    Type = null;
                                }
                                else Type = new IdElement(tokens[current], GetComments());
                                Match(DelphiTokens.Id);
                                Match(DelphiTokens.Do);
                                Statements.Add(new ExceptOnStatementElement(EStart, Id, Type, Statement(false), OptionalElse(), GetComments()));
                                OptionalSemicolon();
                            }
                            List<StatementsElement> Element = new List<StatementsElement>();
                            Element.Add(new StatementsElement(SStart, null, Statements, GetComments()));
                            return new ExceptStatementElement(Start, Element, GetComments());
                        default:
                            return new ExceptStatementElement(Start, OptionalStatements(), GetComments());
                    }
                    break;
                case DelphiTokens.Finally:
                    Match(DelphiTokens.Finally);
                    return new FinallyStatementElement(Start, OptionalStatements(), GetComments());
                default:
                    Panic();
                    return new StatementElement(Start, GetComments());
            }
        }

        /// <summary>
        /// For опция
        /// </summary>
        private void ForOption()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.To:
                case DelphiTokens.Downto:
                    Match(tokens[current].Token);
                    break;
                default:
                    Panic();
                    break;
            }
        }

        /// <summary>
        /// Параметр case
        /// </summary>
        /// <returns>выражение</returns>
        private ExpressionElement CaseParam()
        {
            ExpressionElement Expr = Expression();
            if (MatchTokens(DelphiTokens.Interval))
            {
                Match(DelphiTokens.Interval);
                return new IntervalVariableExpressionElement(Expr.StartInfo, Expr, Expression(), GetComments());
            }
            return Expr;
        }

        /// <summary>
        /// Параметры case
        /// </summary>
        /// <returns>список выражений</returns>
        private List<ExpressionElement> OptionalCaseParams()
        {
            List<ExpressionElement> Params = new List<ExpressionElement>();
            Params.Add(CaseParam());
            while (MatchTokens(DelphiTokens.Comma))
            {
                Match(DelphiTokens.Comma);
                Params.Add(CaseParam());
            }
            return Params;
        }

        /// <summary>
        /// Case блоки
        /// </summary>
        /// <returns>список блоков</returns>
        private List<StatementElement> Cases()
        {
            TokenInfo Start;
            List<StatementElement> Cases = new List<StatementElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Else:
                        Start = tokens[current];
                        Match(tokens[current].Token);
                        Cases.Add(new CaseElseStatementElement(Start, OptionalStatements(), GetComments()));
                        OptionalSemicolon();
                        return Cases;
                    case DelphiTokens.End:
                        return Cases;
                    default:
                        Start = tokens[current];
                        List<ExpressionElement> Params = OptionalCaseParams();
                        Match(DelphiTokens.Colon);
                        if (MatchTokens(DelphiTokens.End))
                        {
                            Cases.Add(new CaseBlockStatementElement(Start, Params, null, GetComments()));
                            return Cases;
                        }
                        Cases.Add(new CaseBlockStatementElement(Start, Params, (!MatchTokens(DelphiTokens.Semicolon)) ? Statement() : null, GetComments()));
                        OptionalSemicolon();
                        break;
                }
            }
        }

        /// <summary>
        /// Возможно at в raise
        /// </summary>
        /// <returns>значение, если at используется</returns>
        private VariableExpressionElement OptionalAt()
        {
            if (MatchTokens(DelphiTokens.At))
            {
                Match(DelphiTokens.At);
                return Variable();
            }
            else return null;
        }

        /// <summary>
        /// Ассемблерный код
        /// </summary>
        /// <returns>соответствующий элемент-блок ассемблерного кода</returns>
        private AsmStatementElement AsmStatement()
        {
            Match(DelphiTokens.Asm);
            AsmStatementElement result = new AsmStatementElement(tokens[current], tokens[current].Text, GetComments());
            Match(tokens[current].Token);
            Match(DelphiTokens.End);
            return result;
        }

        /// <summary>
        /// Команда
        /// </summary>
        /// <param name="MustBe">обязательна или нет</param>
        /// <returns>соответствующий элемент-оператор</returns>
        private StatementElement Statement(bool MustBe)
        {
            if (MatchTokens(MatchAhead(), DelphiTokens.Colon))
                return null;
            TokenInfo SStart = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Asm:
                    return AsmStatement();
                case DelphiTokens.Begin:
                    return CompoundStatement();
                case DelphiTokens.If:
                    Match(DelphiTokens.If);
                    ExpressionElement Expr = Expression();
                    Match(DelphiTokens.Then);
                    return new TestStatementElement(SStart, Expr, this.Statement(false), OptionalElse(), GetComments());
                case DelphiTokens.Try:
                    Match(DelphiTokens.Try);
                    List<StatementsElement> Try = OptionalStatements();
                    StatementElement TryOption = TryOptionBlock();
                    Match(DelphiTokens.End);
                    return new TryStatementElement(SStart, Try, TryOption, GetComments());
                case DelphiTokens.For:
                    Match(DelphiTokens.For);
                    VariableExpressionElement Iterator = this.Variable();
                    Match(DelphiTokens.Assignment);
                    ExpressionElement Start = Expression();
                    TokenInfo Type = tokens[current];
                    ForOption();
                    ExpressionElement End = Expression();
                    Match(DelphiTokens.Do);
                    return new ForStatementElement(SStart, Iterator, Type, Start, End, OptionalStatement(), GetComments());
                case DelphiTokens.While:
                    Match(DelphiTokens.While);
                    ExpressionElement Condition = Expression();
                    Match(DelphiTokens.Do);
                    return new WhileStatementElement(SStart, Condition, OptionalStatement(), GetComments());
                case DelphiTokens.Repeat:
                    Match(DelphiTokens.Repeat);
                    List<StatementsElement> Statement = OptionalStatements();
                    Match(DelphiTokens.Until);
                    return new RepeatStatementElement(SStart, Expression(), Statement, GetComments());
                case DelphiTokens.With:
                    Match(DelphiTokens.With);
                    List<ExpressionElement> Expressions = ExpressionList();
                    Match(DelphiTokens.Do);
                    return new WithStatementExpression(SStart, Expressions, OptionalStatement(), GetComments());
                case DelphiTokens.Case:
                    Match(DelphiTokens.Case);
                    Expr = Expression();
                    Match(DelphiTokens.Of);
                    List<StatementElement> Cases = this.Cases();
                    Match(DelphiTokens.End);
                    return new CaseStatementElement(SStart, Expr, Cases, GetComments());
                case DelphiTokens.Goto:
                    Match(DelphiTokens.Goto);
                    IdElement Label = new IdElement(tokens[current], GetComments());
                    Match(DelphiTokens.Id);
                    return new GotoStatementElement(SStart, Label, GetComments());
                case DelphiTokens.Raise:
                    Match(DelphiTokens.Raise);
                    if (!MatchTokens(DelphiTokens.Semicolon))
                        return new RaiseStatementElement(SStart, this.Variable(), OptionalAt(), GetComments());
                    return new RaiseStatementElement(SStart, null, null, GetComments());
                default:
                    StatementElement Result;
                    bool inherited = MatchTokens(DelphiTokens.Inherited);
                    if (inherited)
                        Match(DelphiTokens.Inherited);
                    TokenInfo VStart = tokens[current];

                    if (MatchTokens(DelphiTokens.Id) || MatchTokens(DelphiTokens.LBr) || MatchTokens(DelphiTokens.AtSign))
                    {
                        VariableExpressionElement Variable = this.Variable();
                        if (MatchTokens(DelphiTokens.Assignment))
                        {
                            Match(DelphiTokens.Assignment);
                            Result = new AssignmentElement(VStart, Variable, Expression(), GetComments());
                        }
                        else Result = new VariableStatementElement(VStart, Variable, GetComments());
                        if (inherited) Result = new InheritedStatementElement(SStart, Result, GetComments());
                        return Result;
                    }
                    else if (inherited) return new InheritedStatementElement(SStart, null, GetComments());
                    else if (MustBe) Panic();
                    break;
            }
            return null;
        }

        /// <summary>
        /// Обязательная команда
        /// </summary>
        /// <returns>соответствующий элемент-оператор</returns>
        private StatementElement Statement()
        {
            return Statement(true);
        }

        /// <summary>
        /// Возможна команда
        /// </summary>
        /// <returns>соответствующий элемент-оператор</returns>
        private StatementElement OptionalStatement()
        {
            return this.Statement(false);
        }

        /// <summary>
        /// Набор команд от 1 и более
        /// </summary>
        /// <returns>список операторов</returns>
        private List<StatementElement> Statements()
        {
            StatementElement Statement;
            List<StatementElement> Statements = new List<StatementElement>();
            Statements.Add(this.Statement());
            while (MatchTokens(DelphiTokens.Semicolon))
            {
                Match(DelphiTokens.Semicolon);
                Statement = OptionalStatement();
                if (Statement != null)
                    Statements.Add(Statement);
            }
            return Statements;
        }

        /// <summary>
        /// Возможен label:
        /// </summary>
        /// <returns>соответствующий элемент-метка</returns>
        private LabelElement OptionalLabel()
        {
            if (MatchTokens(DelphiTokens.Id) && MatchTokens(MatchAhead(), DelphiTokens.Colon))
            {
                LabelElement Label = new LabelElement(tokens[current], GetComments());
                Match(DelphiTokens.Id);
                Match(DelphiTokens.Colon);
                return Label;
            }
            else return null;
        }

        /// <summary>
        /// Возможен набор команд
        /// </summary>
        /// <returns>список операторов</returns>
        private List<StatementsElement> OptionalStatements()
        {
            LabelElement Label;
            List<StatementsElement> Statements = new List<StatementsElement>();
            TokenInfo Start;
            while (true)
            {
                Start = tokens[current];
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Begin:
                    case DelphiTokens.If:
                    case DelphiTokens.Try:
                    case DelphiTokens.For:
                    case DelphiTokens.While:
                    case DelphiTokens.Repeat:
                    case DelphiTokens.With:
                    case DelphiTokens.Case:
                    case DelphiTokens.Goto:
                    case DelphiTokens.Raise:
                    case DelphiTokens.Inherited:
                    case DelphiTokens.LBr:
                    case DelphiTokens.AtSign:
                    case DelphiTokens.Asm:
                        Label = OptionalLabel();
                        Statements.Add(new StatementsElement(Start, Label, this.Statements(), GetComments()));
                        break;
                    default:
                        if (MatchTokens(DelphiTokens.Id))
                        {
                            Label = OptionalLabel();
                            //if (Label != null)
                            //{
                            //    if (tokens[current].Token == DelphiTokens.End)
                            //    {
                            //        LabelOperatorName = Label;
                            //        Label = null;
                            //    }
                            //}
                            Statements.Add(new StatementsElement(Start, Label, this.Statements(), GetComments()));
                        }
                        else return Statements;
                        break;
                }
            }
        }

        private LabelElement LabelOperatorName;
        /// <summary>
        /// Ключевое слово объявления переменной
        /// </summary>
        /// <returns>ключевое слово</returns>
        private TokenInfo VarKeyword()
        {
            TokenInfo KeyWord = null;
            switch (tokens[current].Token)
            {
                case DelphiTokens.Var:
                case DelphiTokens.Threadvar:
                    KeyWord = tokens[current];
                    Match(tokens[current].Token);
                    return KeyWord;
                default:
                    Panic();
                    return KeyWord;
            }
        }

        /// <summary>
        /// Блок объявления переменных
        /// </summary>
        /// <param name="IsStatic">являются ли переменные статичными</param>
        /// <returns>соответствующий элемент-объявление переменных</returns>
        private VarDeclarationsElement VariableDeclaration(bool IsStatic)
        {
            return new VarDeclarationsElement(IsStatic, VarKeyword(), VarDeclarations(), GetComments());
        }

        /// <summary>
        /// Блоки объявления переменных
        /// </summary>
        /// <returns>список блоков объявления переменных</returns>
        private List<VarDeclarationsElement> Vars()
        {
            bool isstatic = MatchTokens(DelphiTokens.Class);
            if (isstatic) Match(DelphiTokens.Class);
            List<VarDeclarationsElement> Vars = new List<VarDeclarationsElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Var:
                    case DelphiTokens.Threadvar:
                        Vars.Add(VariableDeclaration(isstatic));
                        break;
                    default:
                        return Vars;
                }
            }
        }

        /// <summary>
        /// У константы может быть указан тип
        /// </summary>
        /// <returns>соответствующий элемент-константный тип</returns>
        private IConstTypeElement OptionalConstType()
        {
            if (MatchTokens(DelphiTokens.Colon))
            {
                Match(DelphiTokens.Colon);
                return ConstTypeDefinition();
            }
            else return null;
        }

        /// <summary>
        /// Значение константы может быть значением записи
        /// </summary>
        /// <returns>список значений константы</returns>
        private List<ISyntaxTreeElement> RecordValues()
        {
            List<ISyntaxTreeElement> Values = new List<ISyntaxTreeElement>();
            TokenInfo Id;
            while (!MatchTokens(DelphiTokens.RBr))
            {
                Id = tokens[current];
                Match(DelphiTokens.Id);
                Match(DelphiTokens.Colon);
                Values.Add(new RecordConstValueElement(Id, ConstValue(), GetComments()));
                OptionalSemicolon();
            }
            return Values;
        }

        /// <summary>
        /// Значение константы
        /// </summary>
        /// <returns>соответствующий элемент-значение константы</returns>
        private ISyntaxTreeElement ConstValue()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.LBr:
                    TokenInfo Start = tokens[current];
                    ISyntaxTreeElement Value;
                    Match(DelphiTokens.LBr);
                    switch (MatchAhead())
                    {
                        case DelphiTokens.Colon:
                            Value = new ConstValuesElement(Start, RecordValues(), GetComments());
                            break;
                        default:
                            Value = new ConstValuesElement(Start, ConstValues(), GetComments());
                            break;
                    }
                    Match(DelphiTokens.RBr);
                    return Value;
                default:
                    return Expression();
            }
        }

        /// <summary>
        /// Значения константы
        /// </summary>
        /// <returns>список значений константы</returns>
        private List<ISyntaxTreeElement> ConstValues()
        {
            List<ISyntaxTreeElement> Values = new List<ISyntaxTreeElement>();
            Values.Add(ConstValue());
            while (MatchTokens(DelphiTokens.Comma))
            {
                Match(DelphiTokens.Comma);
                Values.Add(ConstValue());
            }
            return Values;
        }

        /// <summary>
        /// Определение константы
        /// </summary>
        /// <returns>соответствующий элемент-определение константы</returns>
        private ConstDefinitionElement ConstantDefinition()
        {
            TokenInfo Id = tokens[current];
            Match(DelphiTokens.Id);
            IConstTypeElement Type = OptionalConstType();
            Match(DelphiTokens.Equal);
            ISyntaxTreeElement Value = ConstValue();
            Match(DelphiTokens.Semicolon);
            return new ConstDefinitionElement(Id, Type, Value, GetComments());
        }

        /// <summary>
        /// Определения констант
        /// </summary>
        /// <returns>спосик определений констант</returns>
        private List<ConstDefinitionElement> ConstantDefinitions()
        {
            List<ConstDefinitionElement> Consts = new List<ConstDefinitionElement>();
            Consts.Add(ConstantDefinition());
            while (MatchTokens(DelphiTokens.Id))
                Consts.Add(ConstantDefinition());
            return Consts;
        }

        /// <summary>
        /// Блок определения констант
        /// </summary>
        /// <returns>соответствующий элемент-определения констант</returns>
        private ConstDefinitionsElement Consts()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Const);
            return new ConstDefinitionsElement(Start, ConstantDefinitions(), GetComments());
        }

        /// <summary>
        /// Возможно наличие in '...' в подключении модуля
        /// </summary>
        /// <returns>соответствующий элемент-in</returns>
        private ConstExpressionElement OptionalUsesIn()
        {
            if (MatchTokens(DelphiTokens.In))
            {
                Match(DelphiTokens.In);
                return Str();
            }
            else return null;
        }

        /// <summary>
        /// Подключение модуля
        /// </summary>
        /// <returns>подключенный модуль</returns>
        private UseElement Unit()
        {
            List<IdElement> Names = new List<IdElement>();
            Names.Add(new IdElement(tokens[current], GetComments()));
            Match(tokens[current].Token);
            while (MatchTokens(DelphiTokens.Dot))
            {
                Match(DelphiTokens.Dot);
                Names.Add(new IdElement(tokens[current], GetComments()));
                Match(tokens[current].Token);
            }
            UseElement Result = new UseElement(Names, OptionalUsesIn(), GetComments());
            string filename = (Result.In == null)
                ? string.Format("{0}\\{1}.pas", new FileInfo(this.file).DirectoryName, Result.Names.Join("."))
                : string.Format("{0}\\{1}", new FileInfo(this.file).DirectoryName, SyntaxTreeElement.TranslateString(Result.In.Tokens));
            if (File.Exists(filename))
                Result.TreeRoot = SyntaxAnalyserController.Instance.Translate(filename, loadIfNeed);
            return Result;
        }

        /// <summary>
        /// Список модулей
        /// </summary>
        /// <returns>список подключенных модулей</returns>
        private List<UseElement> UnitList()
        {
            List<UseElement> Uses = new List<UseElement>();
            Uses.Add(Unit());
            while (MatchTokens(DelphiTokens.Comma))
            {
                Match(DelphiTokens.Comma);
                Uses.Add(Unit());
            }
            return Uses;
        }

        /// <summary>
        /// Секция uses
        /// </summary>
        /// <returns>соответствующий элемент-секция uses</returns>
        private UsesElement Uses()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Uses);
            List<UseElement> Uses = UnitList();
            Match(DelphiTokens.Semicolon);
            return new UsesElement(Start, Uses, GetComments());
        }

        /// <summary>
        /// Возможно наличие секции uses
        /// </summary>
        /// <returns>соответствующий элемент-секция uses</returns>
        private UsesElement OptionalUses()
        {
            if (MatchTokens(DelphiTokens.Uses))
                return Uses();
            else return null;
        }

        /// <summary>
        /// Определение строкового ресурса
        /// </summary>
        /// <returns>соответствующий элемент-определение строкового ресурса</returns>
        private ResourceStringDefinitionElement ResourceStringDefinition()
        {
            TokenInfo Id = tokens[current];
            Match(DelphiTokens.Id);
            Match(DelphiTokens.Equal);
            ResourceStringDefinitionElement ResourceString = new ResourceStringDefinitionElement(Id, SimpleExpression(), GetComments());
            Match(DelphiTokens.Semicolon);
            return ResourceString;
        }

        /// <summary>
        /// Блок объявления строковых ресурсов
        /// </summary>
        /// <returns>соответствующий элемент-объявления строковых ресурсов</returns>
        private ResourceStringDefinitionsElement ResourceStrings()
        {
            List<ResourceStringDefinitionElement> ResourceStrings = new List<ResourceStringDefinitionElement>();
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Resourcestring);
            ResourceStrings.Add(ResourceStringDefinition());
            while (MatchTokens(DelphiTokens.Id))
                ResourceStrings.Add(ResourceStringDefinition());
            return new ResourceStringDefinitionsElement(Start, ResourceStrings, GetComments());
        }

        /// <summary>
        /// Блок объявления меток
        /// </summary>
        /// <returns>соответствующий элемент-объявление метов</returns>
        private LabelDefinitionsElement Labels()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Label);
            LabelDefinitionsElement Labels = new LabelDefinitionsElement(Start, IdList(), GetComments());
            Match(DelphiTokens.Semicolon);
            return Labels;
        }

        /// <summary>
        /// Тело функции
        /// </summary>
        /// <returns>соответствующий элемент-тело метода</returns>
        private MethodBodyElement FunctionBody()
        {
            TokenInfo Start = tokens[current];
            MethodBodyElement Body = new MethodBodyElement(Start, OptionalLocalDeclarations(), Statement(), GetComments());
            Match(DelphiTokens.Semicolon);
            return Body;
        }

        /// <summary>
        /// Определение процедуры
        /// </summary>
        /// <returns>соответствующий элемент-метод</returns>
        private OuterMethodElement ProcedureDefinition()
        {
            OuterProcedureHeadElement Header = OuterProcedureHead();
            MethodBodyElement Body = null;
            if (!Header.External && !Header.Forward)
                Body = FunctionBody();
            return new OuterMethodElement(Header, Body, GetComments());
        }

        /// <summary>
        /// Определение функции
        /// </summary>
        /// <returns>соответствующий элемент-метод</returns>
        private OuterMethodElement FunctionDefinition()
        {
            OuterFunctionHeadElement Header = OuterFunctionHead();
            MethodBodyElement Body = null;
            if (!Header.External && !Header.Forward)
                Body = FunctionBody();
            return new OuterMethodElement(Header, Body, GetComments());
        }

        /// <summary>
        /// Определение классового метода
        /// </summary>
        /// <returns>соответствующий элемент-метод</returns>
        private OuterMethodElement ClassMethodDefinition()
        {
            return new OuterMethodElement(OuterClassMethod(), FunctionBody(), GetComments());
        }

        /// <summary>
        /// Определение оператора
        /// </summary>
        /// <returns>соответствующий элемент-метод</returns>
        private OuterMethodElement OuterRecordOperator()
        {
            Match(DelphiTokens.Class);
            TokenInfo Type = tokens[current];
            Match(DelphiTokens.Operator);
            IdElement RecordName = new IdElement(tokens[current], GetComments());
            Match(DelphiTokens.Id);
            Match(DelphiTokens.Dot);
            TokenInfo MethodName = tokens[current];
            Match(DelphiTokens.Id);
            List<FunctionVarDeclarationElement> Vars = OptionalVars();
            ITypeElement ResultType = null;
            bool typedefined = MatchTokens(DelphiTokens.Colon);
            if (typedefined)
            {
                Match(DelphiTokens.Colon);
                ResultType = SimpleType();
            }
            OuterRecordClassMethodElement Header = new OuterRecordClassMethodElement(Type, RecordName, MethodName, Vars, OptionalDirectives(), ResultType, GetComments());
            Match(DelphiTokens.Semicolon);
            return new OuterMethodElement(Header, FunctionBody(), GetComments());
        }

        /// <summary>
        /// Возможные локальные объявления (локальные переменные, константы и т.д.)
        /// </summary>
        /// <returns>список локальных объявлений</returns>
        private List<ISyntaxTreeElement> OptionalLocalDeclarations()
        {
            List<ISyntaxTreeElement> Declarations = new List<ISyntaxTreeElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Type:
                        Declarations.Add(LocalTypes());
                        break;
                    case DelphiTokens.Const:
                        Declarations.Add(Consts());
                        break;
                    case DelphiTokens.Resourcestring:
                        Declarations.Add(ResourceStrings());
                        break;
                    case DelphiTokens.Var:
                    case DelphiTokens.Threadvar:
                        Declarations.Add(VariableDeclaration(false));
                        break;
                    case DelphiTokens.Label:
                        Declarations.Add(Labels());
                        break;
                    case DelphiTokens.Procedure:
                        Declarations.Add(ProcedureDefinition());
                        break;
                    case DelphiTokens.Function:
                        Declarations.Add(FunctionDefinition());
                        break;
                    default:
                        return Declarations;
                }
            }
        }

        /// <summary>
        /// Интервал значений для свойства
        /// </summary>
        /// <returns>соответствующий элемент-интервал значений</returns>
        private IndexIntervalElement IndexInterval()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.LSBr);
            IndexIntervalElement Result = new IndexIntervalElement(Start, FunctionVariableDeclarations(), GetComments());
            Match(DelphiTokens.RSBr);
            return Result;
        }

        /// <summary>
        /// У свойства может быть интервал значений
        /// </summary>
        /// <returns>соответствующий элемент-интервал значений</returns>
        private IndexIntervalElement OptionalIndexInterval()
        {
            return (MatchTokens(DelphiTokens.LSBr)) ? IndexInterval() : null;
        }

        /// <summary>
        /// У свойства может быть определен тип
        /// </summary>
        /// <returns>соответствующий элемент-тип</returns>
        private ITypeElement OptionalTypeDefinition()
        {
            if (MatchTokens(DelphiTokens.Colon))
            {
                Match(DelphiTokens.Colon);
                return TypeDefinition();
            }
            else return null;
        }

        /// <summary>
        /// Возможна директива index
        /// </summary>
        /// <returns>соответствующий элемент-директива index, если она есть</returns>
        private ConstExpressionElement OptionalIndex()
        {
            if (MatchTokens(DelphiTokens.Index))
            {
                Match(DelphiTokens.Index);
                ConstExpressionElement Index = SignedIInt();
                OptionalSemicolon();
                return Index;
            }
            else return null;
        }

        /// <summary>
        /// Директива read
        /// </summary>
        /// <returns>соответствующий элемент</returns>
        private PropertyOptionElement ReadOption()
        {
            TokenInfo Type = tokens[current];
            Match(DelphiTokens.Read);
            IdElement Id = new IdElement(tokens[current], GetComments());
            Match(DelphiTokens.Id);
            return new PropertyOptionElement(Type, Id, GetComments());
        }

        /// <summary>
        /// Возможно наличие директивы read
        /// </summary>
        /// <returns>соответствующий элемент-директива read</returns>
        private PropertyOptionElement OptionalRead()
        {
            if (MatchTokens(DelphiTokens.Read))
                return ReadOption();
            else return null;
        }

        /// <summary>
        /// Возможно наличие директивы write
        /// </summary>
        /// <returns>соответствующий элемент-директива write</returns>
        private PropertyOptionElement OptionalWrite()
        {
            if (MatchTokens(DelphiTokens.Write))
            {
                TokenInfo Type = tokens[current];
                Match(DelphiTokens.Write);
                IdElement Id = new IdElement(tokens[current], GetComments());
                Match(DelphiTokens.Id);
                return new PropertyOptionElement(Type, Id, GetComments());
            }
            else return null;
        }

        /// <summary>
        /// Возможно наличие директивы stored
        /// </summary>
        /// <returns>соответствующий элемент-директива stored</returns>
        private PropertyOptionElement OptionalStored()
        {
            if (MatchTokens(DelphiTokens.Stored))
            {
                TokenInfo Type = tokens[current];
                Match(DelphiTokens.Stored);
                ISyntaxTreeElement storedvalue;
                switch (tokens[current].Token)
                {
                    case DelphiTokens.True:
                    case DelphiTokens.False:
                        storedvalue = Bool();
                        break;
                    default:
                        storedvalue = new IdElement(tokens[current], GetComments());
                        Match(DelphiTokens.Id);
                        break;
                }
                return new PropertyOptionElement(Type, storedvalue, GetComments());
            }
            else return null;
        }

        /// <summary>
        /// Возможно наличие директивы default/nodefault
        /// </summary>
        /// <returns>соответствующий элемент-директива</returns>
        private PropertyOptionElement OptionalDefault()
        {
            TokenInfo Type = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Default:
                    Match(DelphiTokens.Default);
                    ISyntaxTreeElement Value = null;
                    if (!MatchTokens(DelphiTokens.Semicolon))
                        Value = Expression();
                    return new PropertyOptionElement(Type, Value, GetComments());
                case DelphiTokens.Nodefault:
                    Match(DelphiTokens.Nodefault);
                    return new PropertyOptionElement(Type, null, GetComments());
            }
            return null;
        }

        /// <summary>
        /// Возможно наличие директивы implements
        /// </summary>
        /// <returns>соответствующий элемент-директива implements</returns>
        private PropertyOptionElement OptionalImplements()
        {
            if (MatchTokens(DelphiTokens.Implements))
            {
                TokenInfo Type = tokens[current];
                Match(DelphiTokens.Implements);
                IdElement Id = new IdElement(tokens[current], GetComments());
                Match(DelphiTokens.Id);
                return new PropertyOptionElement(Type, Id, GetComments());
            }
            else return null;
        }

        /// <summary>
        /// Свойство у класса
        /// </summary>
        /// <returns>соответствующий элемент-свойство класса</returns>
        private ClassPropertyElement ClassProperty()
        {
            Match(DelphiTokens.Property);
            TokenInfo Id = tokens[current];
            Match(DelphiTokens.Id);
            IndexIntervalElement IndexInterval = OptionalIndexInterval();
            ITypeElement Type = OptionalTypeDefinition();
            ConstExpressionElement Index = OptionalIndex();
            PropertyOptionElement Read = OptionalRead(),
                Write = OptionalWrite(),
                Stored = OptionalStored(),
                Default = OptionalDefault(),
                Implements = ((IndexInterval == null) && (Index == null) && (Read != null)) ? OptionalImplements() : null;
            bool EndDefault = false;
            Match(DelphiTokens.Semicolon);
            if ((IndexInterval != null) && MatchTokens(DelphiTokens.Default))
            {
                Match(DelphiTokens.Default);
                Match(DelphiTokens.Semicolon);
                EndDefault = true;
            }
            return new ClassPropertyElement(Id, IndexInterval, Type, Index, Read, Write, Stored, Default, Implements, EndDefault, GetComments());
        }

        /// <summary>
        /// Методы класса
        /// </summary>
        /// <returns>список методов класса</returns>
        private List<ISectionElementElement> ClassMethods()
        {
            List<ISectionElementElement> Methods = new List<ISectionElementElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Property:
                        Methods.Add(ClassProperty());
                        break;
                    case DelphiTokens.Procedure:
                    case DelphiTokens.Constructor:
                    case DelphiTokens.Destructor:
                        Methods.Add(InnerProcedureHead());
                        break;
                    case DelphiTokens.Function:
                        Methods.Add(InnerFunctionHead());
                        break;
                    case DelphiTokens.Class:
                        Methods.Add(InnerClassMethod());
                        break;
                    default:
                        return Methods;
                }
            }
        }

        /// <summary>
        /// Секции класса
        /// </summary>
        /// <returns>список секций класса</returns>
        private List<ISectionElement> ClassSections()
        {
            bool strict = false;
            List<ISectionElement> Sections = new List<ISectionElement>();
            TokenInfo Type = null;// new TokenInfo(DelphiTokens.Published, "published", this.file, tokens[current].Line, tokens[current].MetaTags);
            List<ISectionElementElement> Elements;
            bool loop;
            TokenInfo Start;
            while (true)
            {
                Start = tokens[current];
                Elements = new List<ISectionElementElement>();
                loop = true;
                while (loop)
                {
                    if (MatchTokens(DelphiTokens.Id))
                        Elements.AddRange(VarDeclarations().ToArray());
                    else loop = false;
                }
                loop = true;
                while (loop)
                {
                    switch (tokens[current].Token)
                    {
                        case DelphiTokens.Const:
                            Elements.Add(Consts());
                            break;
                        case DelphiTokens.Resourcestring:
                            Elements.Add(ResourceStrings());
                            break;
                        case DelphiTokens.Type:
                            Elements.Add(Types());
                            break;
                        case DelphiTokens.Var:
                            if (MatchTokens(MatchAhead(), DelphiTokens.Id))
                                Elements.AddRange(Vars().ToArray());
                            else Match(DelphiTokens.Var);
                            break;
                        case DelphiTokens.Procedure:
                        case DelphiTokens.Function:
                        case DelphiTokens.Constructor:
                        case DelphiTokens.Destructor:
                        case DelphiTokens.Property:
                            Elements.AddRange(ClassMethods());
                            break;
                        case DelphiTokens.Class:
                            switch (MatchAhead())
                            {
                                case DelphiTokens.Var:
                                    Elements.AddRange(Vars().ToArray());
                                    break;
                                default:
                                    Elements.AddRange(ClassMethods());
                                    break;
                            }
                            break;
                        default:
                            loop = false;
                            break;
                    }
                }
                if (Elements.Count > 0)
                    Sections.Add(new ClassSectionElement(Start, strict, Type, Elements, GetComments()));
                strict = MatchTokens(DelphiTokens.Strict);
                if (strict) Match(DelphiTokens.Strict);
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Published:
                    case DelphiTokens.Public:
                    case DelphiTokens.Protected:
                    case DelphiTokens.Private:
                    case DelphiTokens.Automated:
                        Type = tokens[current];
                        Match(tokens[current].Token);
                        break;
                    default:
                        return Sections;
                }
            }
        }

        /// <summary>
        /// Возможно тело класса
        /// </summary>
        /// <returns>список секций класса</returns>
        private List<ISectionElement> OptionalClassBody()
        {
            if (tokens[current].Token != DelphiTokens.Semicolon)
            {
                List<ISectionElement> Sections = ClassSections();
                Match(DelphiTokens.End);
                return Sections;
            }
            else return null;
        }

        /// <summary>
        /// Класс может быть abstract или sealed
        /// </summary>
        /// <returns>токен abstract или sealed, если он есть</returns>
        private TokenInfo OptionalClassType()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.Abstract:
                case DelphiTokens.Sealed:
                    TokenInfo Directive = tokens[current];
                    Match(tokens[current].Token);
                    return Directive;
            }
            return null;
        }

        /// <summary>
        /// У интерфейса может быть родитель
        /// </summary>
        /// <returns>соответствующий элемент-идентификатор родителя</returns>
        private IdElement OptionalParent()
        {
            if (MatchTokens(DelphiTokens.LBr))
            {
                Match(DelphiTokens.LBr);
                IdElement Parent = new IdElement(tokens[current], GetComments());
                Match(DelphiTokens.Id);
                Match(DelphiTokens.RBr);
                return Parent;
            }
            else return null;
        }

        /// <summary>
        /// У класса могут быть родители
        /// </summary>
        /// <returns>список родителей</returns>
        private List<IdElement> OptionalParents()
        {
            if (MatchTokens(DelphiTokens.LBr))
            {
                Match(DelphiTokens.LBr);
                List<IdElement> Parents = IdList();
                Match(DelphiTokens.RBr);
                return Parents;
            }
            else return null;
        }

        /// <summary>
        /// Определение класса
        /// </summary>
        /// <returns>соответствующий элемент-определение класса</returns>
        private ClassDefinitionElement ClassDefinition()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Class);
            switch (tokens[current].Token)
            {
                case DelphiTokens.Of:
                    Match(DelphiTokens.Of);
                    IdElement Id = new IdElement(tokens[current], GetComments());
                    Match(DelphiTokens.Id);
                    return new ClassOfDefinitionElement(Start, Id, GetComments());
                case DelphiTokens.Semicolon:
                    return new ClassDefinitionElement(Start, GetComments());
                default:
                    return new FullClassDefinitionElement(Start, OptionalClassType(), OptionalParents(), OptionalClassBody(), GetComments());
                    break;
            }
        }

        /// <summary>
        /// Оператор в записи
        /// </summary>
        /// <returns>соответствующий элемент-оператор записи</returns>
        private InnerRecordClassMethodElement RecordOperator()
        {
            Match(DelphiTokens.Class);
            TokenInfo Type = tokens[current];
            Match(DelphiTokens.Operator);
            TokenInfo Name = tokens[current];
            Match(DelphiTokens.Id);
            List<FunctionVarDeclarationElement> Vars = OptionalVars();
            ITypeElement ResultType = null;
            bool typedefined = MatchTokens(DelphiTokens.Colon);
            if (typedefined)
            {
                Match(DelphiTokens.Colon);
                ResultType = SimpleType();
            }
            InnerRecordClassMethodElement Result = new InnerRecordClassMethodElement(Type, Name, Vars, OptionalDirectives(), ResultType, GetComments());
            Match(DelphiTokens.Semicolon);
            return Result;
        }

        /// <summary>
        /// Методы записи
        /// </summary>
        /// <returns>список методов записи</returns>
        private List<ISectionElementElement> RecordMethods()
        {
            List<ISectionElementElement> Methods = new List<ISectionElementElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Property:
                        Methods.Add(ClassProperty());
                        break;
                    case DelphiTokens.Procedure:
                        Methods.Add(InnerProcedureHead());
                        break;
                    case DelphiTokens.Function:
                        Methods.Add(InnerFunctionHead());
                        break;
                    case DelphiTokens.Class:
                        Methods.Add(RecordOperator());
                        break;
                    default:
                        return Methods;
                }
            }
        }

        /// <summary>
        /// Элемент блока case
        /// </summary>
        /// <returns>соответствующий элемент-элемент блока case</returns>
        private RecordCaseBlockElement RecordCaseBlock()
        {
            TokenInfo Start = tokens[current];
            List<ExpressionElement> Params = ExpressionList();
            Match(DelphiTokens.Colon);
            Match(DelphiTokens.LBr);
            List<VarDeclarationElement> Vars = VarDeclarations(false);
            Match(DelphiTokens.RBr);
            OptionalSemicolon();
            return new RecordCaseBlockElement(Start, Params, Vars, GetComments());
        }

        /// <summary>
        /// Элементы блока case
        /// </summary>
        /// <returns>список элементов блока case</returns>
        private List<RecordCaseBlockElement> RecordCaseBlocks()
        {
            List<RecordCaseBlockElement> Blocks = new List<RecordCaseBlockElement>();
            while (!MatchTokens(DelphiTokens.End))
                Blocks.Add(RecordCaseBlock());
            return Blocks;
        }

        /// <summary>
        /// case внутри записи
        /// </summary>
        /// <returns>соответствующий элемент-блок case</returns>
        private RecordCaseElement RecordCase()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Case);
            List<PartOfStandartVariableExpressionElement> Parts = new List<PartOfStandartVariableExpressionElement>();
            Parts.Add(new PartOfStandartVariableExpressionElement(tokens[current], tokens[current], null, GetComments()));
            ITypeElement Type = new IntervalCommonTypeElement(tokens[current], new IntervalVariableExpressionElement(tokens[current], new StandartVariableExpressionElement(tokens[current], null, Parts, GetComments()), null, GetComments()), GetComments());
            Match(tokens[current].Token);
            Match(DelphiTokens.Of);
            List<TokenInfo> Comments = GetComments();
            List<RecordCaseBlockElement> Blocks = RecordCaseBlocks();
            if (Comments == null) Comments = GetComments();
            else Comments.AddRangeNotNull(GetComments());
            return new RecordCaseElement(Start, Type, Blocks, Comments);
        }

        /// <summary>
        /// Определение записи
        /// </summary>
        /// <returns>соответствующий элемент-определение записи</returns>
        private RecordElement RecordDefinition()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Record);
            List<ISectionElementElement> Elements = new List<ISectionElementElement>();
            bool loop = true;
            while (loop)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Id:
                        Elements.AddRange(VarDeclarations(false).ToArray());
                        break;
                    default:
                        loop = false;
                        break;
                }
            }
            loop = true;
            while (loop)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Procedure:
                    case DelphiTokens.Function:
                    case DelphiTokens.Property:
                    case DelphiTokens.Class:
                        Elements.AddRange(RecordMethods());
                        break;
                    default:
                        loop = false;
                        break;
                }
            }
            if (MatchTokens(DelphiTokens.Case))
                Elements.Add(RecordCase());
            Match(DelphiTokens.End);
            return new RecordElement(Start, Elements, GetComments());
        }

        /// <summary>
        /// Определение записи-константы
        /// </summary>
        /// <returns>соответствующий элемент-определение константной записи</returns>
        private RecordConstTypeElement ConstRecordDefinition()
        {
            List<VarDeclarationElement> Elements = null;
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Record);
            if (MatchTokens(DelphiTokens.Id))
                Elements = VarDeclarations();
            Match(DelphiTokens.End);
            return new RecordConstTypeElement(Start, Elements, GetComments());
        }

        /// <summary>
        /// Определение константы
        /// </summary>
        /// <returns>соответствующий элемент-определение константы</returns>
        private ObjectDefinitionElement ObjectDefinition()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Object);
            ObjectDefinitionElement Obj = new ObjectDefinitionElement(Start, OptionalClassType(), OptionalParents(), ClassSections(), GetComments());
            Match(DelphiTokens.End);
            return Obj;
        }

        /// <summary>
        /// GUID
        /// </summary>
        /// <returns>соответствующий элемент-выражение</returns>
        private ConstExpressionElement Guid()
        {
            Match(DelphiTokens.LSBr);
            ConstExpressionElement Guid = Str();
            Match(DelphiTokens.RSBr);
            return Guid;
        }

        /// <summary>
        /// Возможен GUID
        /// </summary>
        /// <returns>соответствующий элемент-выражение</returns>
        private ConstExpressionElement OptionalGuid()
        {
            if (MatchTokens(DelphiTokens.LSBr))
                return Guid();
            else return null;
        }

        /// <summary>
        /// Интерфейсное свойство
        /// </summary>
        /// <returns>соответствующий элемент-свойство интерфейса</returns>
        private InterfacePropertyElement InterfaceProperty()
        {
            Match(DelphiTokens.Property);
            TokenInfo Id = tokens[current];
            Match(DelphiTokens.Id);
            InterfacePropertyElement Result = new InterfacePropertyElement(Id, OptionalIndexInterval(), OptionalTypeDefinition(), OptionalIndex(), OptionalRead(), OptionalWrite(), OptionalStored(), OptionalDefault(), GetComments());
            Match(DelphiTokens.Semicolon);
            return Result;
        }

        /// <summary>
        /// Определение интерфейса
        /// </summary>
        /// <returns>соответствующий элемент-определение интерфейса</returns>
        private InterfaceDefinitionElement InterfaceDefinition()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Interface);
            IdElement Parent = OptionalParent();
            ConstExpressionElement Guid = OptionalGuid();
            List<ISectionElementElement> Elements = new List<ISectionElementElement>();
            bool loop = true;
            while (loop)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Property:
                        Elements.Add(InterfaceProperty());
                        break;
                    case DelphiTokens.Procedure:
                        Elements.Add(InnerProcedureHead());
                        break;
                    case DelphiTokens.Function:
                        Elements.Add(InnerFunctionHead());
                        break;
                    default:
                        loop = false;
                        break;
                }
            }
            if ((Parent != null) || (Guid != null) || (Elements.Count > 0)) Match(DelphiTokens.End);
            return new InterfaceDefinitionElement(Start, Parent, Guid, Elements, GetComments());
        }

        /// <summary>
        /// Возможна директива dispid
        /// </summary>
        /// <returns>соответствующий элемент-директива</returns>
        private PropertyOptionElement OptionalDispid()
        {
            if (MatchTokens(DelphiTokens.Dispid))
            {
                TokenInfo Type = tokens[current];
                Match(DelphiTokens.Dispid);
                return new PropertyOptionElement(Type, SignedIInt(), GetComments());
            }
            return null;
        }

        /// <summary>
        /// Директива dispid может быть в конце
        /// </summary>
        /// <returns>соответствующий элемент-директива</returns>
        private PropertyOptionElement OptionalDispidEnd()
        {
            if (MatchTokens(DelphiTokens.Dispid))
            {
                PropertyOptionElement Dispid = OptionalDispid();
                Match(DelphiTokens.Semicolon);
                return Dispid;
            }
            return null;
        }

        /// <summary>
        /// Возможна директива default
        /// </summary>
        /// <returns>наличие директивы</returns>
        private bool OptionalDispDefault()
        {
            if (MatchTokens(DelphiTokens.Default))
            {
                Match(DelphiTokens.Default);
                Match(DelphiTokens.Semicolon);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Возможна директива readonly
        /// </summary>
        /// <returns>наличие директивы</returns>
        private bool OptionalReadOnly()
        {
            if (MatchTokens(DelphiTokens.ReadOnly))
            {
                Match(DelphiTokens.ReadOnly);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Свойство Dispatch-интерфейса
        /// </summary>
        /// <returns>соответствующий элемент-свойство</returns>
        private DispinterfacePropertyElement DispinterfaceProperty()
        {
            Match(DelphiTokens.Property);
            TokenInfo Id = tokens[current];
            Match(DelphiTokens.Id);
            IndexIntervalElement IndexInterval = OptionalIndexInterval();
            ITypeElement Type = OptionalTypeDefinition();
            bool IsReadOnly = OptionalReadOnly();
            PropertyOptionElement Dispid = OptionalDispid();
            Match(DelphiTokens.Semicolon);
            return new DispinterfacePropertyElement(Id, IndexInterval, IsReadOnly, Dispid, (IndexInterval != null) ? OptionalDispDefault() : false, GetComments());
        }

        /// <summary>
        /// Секция Dispatch-интерфейса
        /// </summary>
        /// <returns>соответствующий элемент-секция</returns>
        private List<ISectionElementElement> DispinterfaceSection()
        {
            List<ISectionElementElement> Elements = new List<ISectionElementElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Property:
                        Elements.Add(DispinterfaceProperty());
                        break;
                    case DelphiTokens.Procedure:
                        Elements.Add(DispinterfaceProcedureHead());
                        break;
                    case DelphiTokens.Function:
                        Elements.Add(DispinterfaceFunctionHead());
                        break;
                    default:
                        return Elements;
                }
            }
        }

        /// <summary>
        /// Определение Dispatch-интерфейса
        /// </summary>
        /// <returns>соответствующий элемент-опредеоение</returns>
        private DispinterfaceDefinitionElement DispinterfaceDefinition()
        {
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Dispinterface);
            switch (tokens[current].Token)
            {
                case DelphiTokens.Semicolon:
                    return new DispinterfaceDefinitionElement(Start, GetComments());
                    break;
                default:
                    FullDispinterfaceDefinitionElement Result = new FullDispinterfaceDefinitionElement(Start, Guid(), DispinterfaceSection(), GetComments());
                    Match(DelphiTokens.End);
                    return Result;
            }
        }

        /// <summary>
        /// Определение типа (любого)
        /// </summary>
        /// <returns>соответствующий элемент-определение типа</returns>
        private ITypeElement FullTypeDefinition()
        {
            switch (tokens[current].Token)
            {
                case DelphiTokens.Class:
                    return ClassDefinition();
                case DelphiTokens.Object:
                    return ObjectDefinition();
                case DelphiTokens.Interface:
                    return InterfaceDefinition();
                case DelphiTokens.Dispinterface:
                    return DispinterfaceDefinition();
                default:
                    return TypeDefinition();
            }
        }

        /// <summary>
        /// Локальные типы
        /// </summary>
        /// <returns>соответствующий элемент-определение локального типа</returns>
        private TypeDeclarationsElement LocalTypes()
        {
            TokenInfo Id;
            List<TypeDeclarationElement> Declarations = new List<TypeDeclarationElement>();
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Type);
            while (true)
            {
                if (MatchTokens(DelphiTokens.Id))
                {
                    Id = tokens[current];
                    Match(DelphiTokens.Id);
                    Match(DelphiTokens.Equal);
                    bool Typed = MatchTokens(DelphiTokens.Type);
                    if (Typed) Match(DelphiTokens.Type);
                    Declarations.Add(new TypeDeclarationElement(Id, Typed, TypeDefinition(), GetComments()));
                    Match(DelphiTokens.Semicolon);
                }
                else return new TypeDeclarationsElement(Start, Declarations, GetComments());
            }
        }

        /// <summary>
        /// Блок определения типа
        /// </summary>
        /// <returns>соответствующий элемент-определение типов</returns>
        private TypeDeclarationsElement Types()
        {
            TokenInfo Id;
            List<TypeDeclarationElement> Declarations = new List<TypeDeclarationElement>();
            TokenInfo Start = tokens[current];
            Match(DelphiTokens.Type);
            while (MatchTokens(DelphiTokens.Id))
            {
                Id = tokens[current];
                Match(DelphiTokens.Id);
                Match(DelphiTokens.Equal);
                bool Typed = MatchTokens(DelphiTokens.Type);
                if (Typed) Match(DelphiTokens.Type);
                Declarations.Add(new TypeDeclarationElement(Id, Typed, FullTypeDefinition(), GetComments()));
                Match(DelphiTokens.Semicolon);
            }
            return new TypeDeclarationsElement(Start, Declarations, GetComments());
        }

        /// <summary>
        /// Возможен блок определения типа
        /// </summary>
        /// <returns>соответствующий элемент-определения типов</returns>
        private TypeDeclarationsElement OptionalTypes()
        {
            if (MatchTokens(DelphiTokens.Type))
                return Types();
            else return null;
        }

        /// <summary>
        /// Блок интерфейсной части модуля
        /// </summary>
        /// <returns>список объявлений</returns>
        private List<ISyntaxTreeElement> InterfaceBlocks()
        {
            List<ISyntaxTreeElement> Blocks = new List<ISyntaxTreeElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Const:
                        Blocks.Add(Consts());
                        break;
                    case DelphiTokens.Type:
                        Blocks.Add(Types());
                        break;
                    case DelphiTokens.Var:
                    case DelphiTokens.Threadvar:
                        Blocks.AddRange(Vars().ToArray());
                        break;
                    case DelphiTokens.Resourcestring:
                        Blocks.Add(ResourceStrings());
                        break;
                    case DelphiTokens.Label:
                        Blocks.Add(Labels());
                        break;
                    case DelphiTokens.Procedure:
                        Blocks.Add(InnerProcedureHead());
                        break;
                    case DelphiTokens.Function:
                        Blocks.Add(InnerFunctionHead());
                        break;
                    default:
                        return Blocks;
                }
            }
        }

        /// <summary>
        /// Блок определения
        /// </summary>
        /// <returns>список определений</returns>
        private List<ISyntaxTreeElement> ImplementationBlocks()
        {
            List<ISyntaxTreeElement> Implementations = new List<ISyntaxTreeElement>();
            while (true)
            {
                switch (tokens[current].Token)
                {
                    case DelphiTokens.Uses:
                        Implementations.Add(Uses());
                        break;
                    case DelphiTokens.Const:
                        Implementations.Add(Consts());
                        break;
                    case DelphiTokens.Type:
                        Implementations.Add(Types());
                        break;
                    case DelphiTokens.Var:
                    case DelphiTokens.Threadvar:
                        Implementations.AddRange(Vars().ToArray());
                        break;
                    case DelphiTokens.Resourcestring:
                        Implementations.Add(ResourceStrings());
                        break;
                    case DelphiTokens.Label:
                        Implementations.Add(Labels());
                        break;
                    case DelphiTokens.Constructor:
                    case DelphiTokens.Destructor:
                    case DelphiTokens.Procedure:
                        Implementations.Add(ProcedureDefinition());
                        break;
                    case DelphiTokens.Function:
                        Implementations.Add(FunctionDefinition());
                        break;
                    case DelphiTokens.Class:
                        switch (MatchAhead())
                        {
                            case DelphiTokens.Operator:
                                Implementations.Add(OuterRecordOperator());
                                break;
                            case DelphiTokens.Procedure:
                            case DelphiTokens.Function:
                                Implementations.Add(ClassMethodDefinition());
                                break;
                            default:
                                Panic();
                                break;
                        }
                        break;
                    default:
                        return Implementations;
                }
            }
        }

        /// <summary>
        /// Возможен блок инициализации
        /// </summary>
        /// <returns>список операторов</returns>
        private List<StatementsElement> OptionalInitialization()
        {
            if (MatchTokens(DelphiTokens.Initialization))
            {
                Match(DelphiTokens.Initialization);
                return OptionalStatements();
            }
            else return null;
        }

        /// <summary>
        /// Возможен блок финализации
        /// </summary>
        /// <returns>список операторов</returns>
        private List<StatementsElement> OptionalFinalization()
        {
            if (MatchTokens(DelphiTokens.Finalization))
            {
                Match(DelphiTokens.Finalization);
                return OptionalStatements();
            }
            else return null;
        }

        /// <summary>
        /// Возможна опция resident при экспорте функций
        /// </summary>
        /// <returns>наличие директивы</returns>
        private bool OptionalResident()
        {
            if (MatchTokens(DelphiTokens.Resident))
            {
                Match(DelphiTokens.Resident);
                return true;
            }
            else return false;
        }

        /// <summary>
        /// Возможна опция параметров экспорта
        /// </summary>
        /// <returns>соответствующий элемент-параметр экспорта</returns>
        private ExportByElement OptionalExportBy()
        {
            TokenInfo Start, Option = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Index:
                    Match(DelphiTokens.Index);
                    Start = tokens[current];
                    return new ExportByElement(Option, new ConstExpressionElement(Start, IInt(), GetComments()), false, GetComments());
                case DelphiTokens.Name:
                    Match(DelphiTokens.Name);
                    return new ExportByElement(Option, Str(), OptionalResident(), GetComments());
            }
            return null;
        }

        /// <summary>
        /// Возможен блок экспорта функций
        /// </summary>
        /// <returns>список экспортов</returns>
        private List<ExportsElement> OptionalExports()
        {
            TokenInfo Id;
            List<ExportsElementElement> Elements;
            List<ExportsElement> Exports = new List<ExportsElement>();
            TokenInfo Start;
            while (MatchTokens(DelphiTokens.Exports))
            {
                Start = tokens[current];
                Match(DelphiTokens.Exports);
                Elements = new List<ExportsElementElement>();
                while (true)
                {
                    Id = tokens[current];
                    Match(DelphiTokens.Id);
                    Elements.Add(new ExportsElementElement(Id, OptionalExportBy(), GetComments()));
                    if (!MatchTokens(DelphiTokens.Comma)) break;
                    Match(DelphiTokens.Comma);
                }
                Match(DelphiTokens.Semicolon);
                Exports.Add(new ExportsElement(Start, Elements, GetComments()));
            }
            return Exports;
        }

        /// <summary>
        /// Возможно наличие параметров программы
        /// </summary>
        /// <returns>список параметров</returns>
        private List<IdElement> OptionalParams()
        {
            if (MatchTokens(DelphiTokens.LBr))
            {
                Match(DelphiTokens.LBr);
                List<IdElement> Params = IdList();
                Match(DelphiTokens.RBr);
                return Params;
            }
            else return null;
        }

        /// <summary>
        /// В конце проектного файла возможен блок begin/end или просто end
        /// </summary>
        /// <returns>соответсвующий элемент-блок кода</returns>
        private CompoundStatementElement OptionalProgramCompound()
        {
            if (MatchTokens(DelphiTokens.Begin))
                return CompoundStatement();
            Match(DelphiTokens.End);
            return null;
        }

        /// <summary>
        /// Трансляция файла
        /// </summary>
        /// <returns>корень дерева файла</returns>
        private FileElement Translate()
        {
            IdElement Name;
            FileElement root = null;
            Match(DelphiTokens.Undefined);
            TokenInfo Start = tokens[current];
            switch (tokens[current].Token)
            {
                case DelphiTokens.Program:
                    Match(DelphiTokens.Program);
                    Name = new IdElement(tokens[current], GetComments());
                    Match(DelphiTokens.Id);
                    List<IdElement> Params = OptionalParams();
                    Match(DelphiTokens.Semicolon);
                    root = new ProgramElement(Start, new FileInfo(this.file).Name, Name, Params, OptionalUses(), ImplementationBlocks(), OptionalProgramCompound(), GetComments());
                    Match(DelphiTokens.Dot);
                    break;
                case DelphiTokens.Unit:
                    Match(DelphiTokens.Unit);
                    Name = new IdElement(tokens[current], GetComments());
                    Match(DelphiTokens.Id);
                    Match(DelphiTokens.Semicolon);
                    TypeDeclarationsElement Types = OptionalTypes();
                    Match(DelphiTokens.Interface);
                    UsesElement Uses = OptionalUses();
                    List<ISyntaxTreeElement> Interfaces = InterfaceBlocks();
                    Match(DelphiTokens.Implementation);
                    root = new UnitElement(Start, new FileInfo(this.file).Name, Name, Uses, Types, Interfaces, ImplementationBlocks(), OptionalInitialization(), OptionalFinalization(), GetComments());
                    Match(DelphiTokens.End);
                    Match(DelphiTokens.Dot);
                    break;
                case DelphiTokens.Library:
                    Match(DelphiTokens.Library);
                    Name = new IdElement(tokens[current], GetComments());
                    Match(DelphiTokens.Id);
                    Match(DelphiTokens.Semicolon);
                    root = new LibraryElement(Start, new FileInfo(this.file).Name, Name, OptionalUses(), ImplementationBlocks(), OptionalExports(), CompoundStatement(), GetComments());
                    Match(DelphiTokens.Dot);
                    break;
                default:
                    Panic();
                    break;
            }
            return root;
        }

        /// <summary>
        /// Получение участка кода, содержащего ошибку
        /// </summary>
        /// <returns>код, содержащий ошибку</returns>
        private string GetCode()
        {
            int first = current - 6,
                last = current + 6;
            if (first < 0)
            {
                last -= first;
                first = 0;
            }
            if (last >= tokens.Count)
            {
                first -= last - tokens.Count + 1;
                last = tokens.Count - 1;
                if (first < 0) first = 0;
            }
            string result = string.Empty;
            for (int i = first; i <= last; i++)
                result += string.Format("{0} ", tokens[i].Text);
            return result;
        }

        /// <summary>
        /// Трансляция
        /// </summary>
        /// <param name="file">информация о транслируемом файле</param>
        /// <param name="loadIfNeed">подружать подключаемые модули для трансляции</param>
        /// <returns>корень синтаксического дерева</returns>
        public FileElement Translate(string file, bool loadIfNeed)
        {
            try
            {
                Initialize(file, loadIfNeed);
                return Translate();
            }
            catch (Exception e)
            {
                if (e is DanalyserError)
                    AddError(tokens[current].Line, GetCode(), tokens[current].MetaTags);
                else AddUndefinedError(file, tokens[current].Line, GetCode(), tokens[current].MetaTags);
            }
            return null;
        }
    }
}
